diff options
author | Noah Goldstein <goldstein.w.n@gmail.com> | 2024-03-13 13:13:52 -0700 |
---|---|---|
committer | Fangrui Song <i@maskray.me> | 2024-03-13 13:13:52 -0700 |
commit | 9ce8691dea8dadc1302abacf4302f3b805e1448d (patch) | |
tree | fdc2da3081156b4c9b80b0d417f090efadac946c /clang/lib | |
parent | 795e3c3d94da0a664642d4580d87c82c02d5eca4 (diff) | |
parent | 744a23f24b08e8b988b176173c433d64761e66b3 (diff) | |
download | llvm-users/MaskRay/spr/main.llvm-objcopy-add-compress-sections.zip llvm-users/MaskRay/spr/main.llvm-objcopy-add-compress-sections.tar.gz llvm-users/MaskRay/spr/main.llvm-objcopy-add-compress-sections.tar.bz2 |
[𝘀𝗽𝗿] changes introduced through rebaseusers/MaskRay/spr/main.llvm-objcopy-add-compress-sections
Created using spr 1.3.5-bogner
[skip ci]
Diffstat (limited to 'clang/lib')
25 files changed, 412 insertions, 157 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 8626f04..95900af 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2577,11 +2577,14 @@ APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes, bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, Ctx, this, Notes, IsConstantInitialization); - // In C++/C23, this isn't a constant initializer if we produced notes. In that - // case, we can't keep the result, because it may only be correct under the - // assumption that the initializer is a constant context. + // In C++, or in C23 if we're initialising a 'constexpr' variable, this isn't + // a constant initializer if we produced notes. In that case, we can't keep + // the result, because it may only be correct under the assumption that the + // initializer is a constant context. if (IsConstantInitialization && - (Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23) && !Notes.empty()) + (Ctx.getLangOpts().CPlusPlus || + (isConstexpr() && Ctx.getLangOpts().C23)) && + !Notes.empty()) Result = false; // Ensure the computed APValue is cleaned up later if evaluation succeeded, diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 726415c..b154a19 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8517,6 +8517,53 @@ public: }; } // end anonymous namespace +/// Get an lvalue to a field of a lambda's closure type. +static bool HandleLambdaCapture(EvalInfo &Info, const Expr *E, LValue &Result, + const CXXMethodDecl *MD, const FieldDecl *FD, + bool LValueToRValueConversion) { + // Static lambda function call operators can't have captures. We already + // diagnosed this, so bail out here. + if (MD->isStatic()) { + assert(Info.CurrentCall->This == nullptr && + "This should not be set for a static call operator"); + return false; + } + + // Start with 'Result' referring to the complete closure object... + if (MD->isExplicitObjectMemberFunction()) { + // Self may be passed by reference or by value. + const ParmVarDecl *Self = MD->getParamDecl(0); + if (Self->getType()->isReferenceType()) { + APValue *RefValue = Info.getParamSlot(Info.CurrentCall->Arguments, Self); + Result.setFrom(Info.Ctx, *RefValue); + } else { + const ParmVarDecl *VD = Info.CurrentCall->Arguments.getOrigParam(Self); + CallStackFrame *Frame = + Info.getCallFrameAndDepth(Info.CurrentCall->Arguments.CallIndex) + .first; + unsigned Version = Info.CurrentCall->Arguments.Version; + Result.set({VD, Frame->Index, Version}); + } + } else + Result = *Info.CurrentCall->This; + + // ... then update it to refer to the field of the closure object + // that represents the capture. + if (!HandleLValueMember(Info, E, Result, FD)) + return false; + + // And if the field is of reference type (or if we captured '*this' by + // reference), update 'Result' to refer to what + // the field refers to. + if (LValueToRValueConversion) { + APValue RVal; + if (!handleLValueToRValueConversion(Info, E, FD->getType(), Result, RVal)) + return false; + Result.setFrom(Info.Ctx, RVal); + } + return true; +} + /// Evaluate an expression as an lvalue. This can be legitimately called on /// expressions which are not glvalues, in three cases: /// * function designators in C, and @@ -8561,37 +8608,8 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { if (auto *FD = Info.CurrentCall->LambdaCaptureFields.lookup(VD)) { const auto *MD = cast<CXXMethodDecl>(Info.CurrentCall->Callee); - - // Static lambda function call operators can't have captures. We already - // diagnosed this, so bail out here. - if (MD->isStatic()) { - assert(Info.CurrentCall->This == nullptr && - "This should not be set for a static call operator"); - return false; - } - - // Start with 'Result' referring to the complete closure object... - if (MD->isExplicitObjectMemberFunction()) { - APValue *RefValue = - Info.getParamSlot(Info.CurrentCall->Arguments, MD->getParamDecl(0)); - Result.setFrom(Info.Ctx, *RefValue); - } else - Result = *Info.CurrentCall->This; - - // ... then update it to refer to the field of the closure object - // that represents the capture. - if (!HandleLValueMember(Info, E, Result, FD)) - return false; - // And if the field is of reference type, update 'Result' to refer to what - // the field refers to. - if (FD->getType()->isReferenceType()) { - APValue RVal; - if (!handleLValueToRValueConversion(Info, E, FD->getType(), Result, - RVal)) - return false; - Result.setFrom(Info.Ctx, RVal); - } - return true; + return HandleLambdaCapture(Info, E, Result, MD, FD, + FD->getType()->isReferenceType()); } } @@ -9069,45 +9087,46 @@ public: return Error(E); } bool VisitCXXThisExpr(const CXXThisExpr *E) { - // Can't look at 'this' when checking a potential constant expression. - if (Info.checkingPotentialConstantExpression()) - return false; - if (!Info.CurrentCall->This) { + auto DiagnoseInvalidUseOfThis = [&] { if (Info.getLangOpts().CPlusPlus11) Info.FFDiag(E, diag::note_constexpr_this) << E->isImplicit(); else Info.FFDiag(E); + }; + + // Can't look at 'this' when checking a potential constant expression. + if (Info.checkingPotentialConstantExpression()) return false; + + bool IsExplicitLambda = + isLambdaCallWithExplicitObjectParameter(Info.CurrentCall->Callee); + if (!IsExplicitLambda) { + if (!Info.CurrentCall->This) { + DiagnoseInvalidUseOfThis(); + return false; + } + + Result = *Info.CurrentCall->This; } - Result = *Info.CurrentCall->This; if (isLambdaCallOperator(Info.CurrentCall->Callee)) { // Ensure we actually have captured 'this'. If something was wrong with // 'this' capture, the error would have been previously reported. // Otherwise we can be inside of a default initialization of an object // declared by lambda's body, so no need to return false. - if (!Info.CurrentCall->LambdaThisCaptureField) - return true; - - // If we have captured 'this', the 'this' expression refers - // to the enclosing '*this' object (either by value or reference) which is - // either copied into the closure object's field that represents the - // '*this' or refers to '*this'. - // Update 'Result' to refer to the data member/field of the closure object - // that represents the '*this' capture. - if (!HandleLValueMember(Info, E, Result, - Info.CurrentCall->LambdaThisCaptureField)) - return false; - // If we captured '*this' by reference, replace the field with its referent. - if (Info.CurrentCall->LambdaThisCaptureField->getType() - ->isPointerType()) { - APValue RVal; - if (!handleLValueToRValueConversion(Info, E, E->getType(), Result, - RVal)) + if (!Info.CurrentCall->LambdaThisCaptureField) { + if (IsExplicitLambda && !Info.CurrentCall->This) { + DiagnoseInvalidUseOfThis(); return false; + } - Result.setFrom(Info.Ctx, RVal); + return true; } + + const auto *MD = cast<CXXMethodDecl>(Info.CurrentCall->Callee); + return HandleLambdaCapture( + Info, E, Result, MD, Info.CurrentCall->LambdaThisCaptureField, + Info.CurrentCall->LambdaThisCaptureField->getType()->isPointerType()); } return true; } diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index bb22065..db80e2d 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -846,8 +846,7 @@ bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) { CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult)); assert(CmpValueInfo); assert(CmpValueInfo->hasValidIntValue()); - const APSInt &IntValue = CmpValueInfo->getIntValue(); - return SetThreeWayComparisonField(S, OpPC, P, IntValue); + return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue()); } template <PrimType Name, class T = typename PrimConv<Name>::T> diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index 9f597dc..256365d 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -301,10 +301,9 @@ bool Module::directlyUses(const Module *Requested) { if (Requested->isSubModuleOf(Use)) return true; - // Anyone is allowed to use our builtin stdarg.h and stddef.h and their - // accompanying modules. - if (Requested->getTopLevelModuleName() == "_Builtin_stdarg" || - Requested->getTopLevelModuleName() == "_Builtin_stddef") + // Anyone is allowed to use our builtin stddef.h and its accompanying modules. + if (Requested->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}) || + Requested->fullModuleNameIs({"_Builtin_stddef_wint_t"})) return true; if (NoUndeclaredIncludes) diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index bbe14ef..dc42faf 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -284,6 +284,7 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( setTLSMode(GV, D); setGVProperties(GV, &D); + getTargetCodeGenInfo().setTargetAttributes(cast<Decl>(&D), GV, *this); // Make sure the result is of the correct type. LangAS ExpectedAS = Ty.getAddressSpace(); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 967319b..8ceecff 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -626,6 +626,26 @@ static bool checkAliasedGlobal( return true; } +// Emit a warning if toc-data attribute is requested for global variables that +// have aliases and remove the toc-data attribute. +static void checkAliasForTocData(llvm::GlobalVariable *GVar, + const CodeGenOptions &CodeGenOpts, + DiagnosticsEngine &Diags, + SourceLocation Location) { + if (GVar->hasAttribute("toc-data")) { + auto GVId = GVar->getName(); + // Is this a global variable specified by the user as local? + if ((llvm::binary_search(CodeGenOpts.TocDataVarsUserSpecified, GVId))) { + Diags.Report(Location, diag::warn_toc_unsupported_type) + << GVId << "the variable has an alias"; + } + llvm::AttributeSet CurrAttributes = GVar->getAttributes(); + llvm::AttributeSet NewAttributes = + CurrAttributes.removeAttribute(GVar->getContext(), "toc-data"); + GVar->setAttributes(NewAttributes); + } +} + void CodeGenModule::checkAliases() { // Check if the constructed aliases are well formed. It is really unfortunate // that we have to do this in CodeGen, but we only construct mangled names @@ -652,6 +672,12 @@ void CodeGenModule::checkAliases() { continue; } + if (getContext().getTargetInfo().getTriple().isOSAIX()) + if (const llvm::GlobalVariable *GVar = + dyn_cast<const llvm::GlobalVariable>(GV)) + checkAliasForTocData(const_cast<llvm::GlobalVariable *>(GVar), + getCodeGenOpts(), Diags, Location); + llvm::Constant *Aliasee = IsIFunc ? cast<llvm::GlobalIFunc>(Alias)->getResolver() : cast<llvm::GlobalAlias>(Alias)->getAliasee(); diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp index 40dddde..00b0472 100644 --- a/clang/lib/CodeGen/Targets/PPC.cpp +++ b/clang/lib/CodeGen/Targets/PPC.cpp @@ -8,6 +8,7 @@ #include "ABIInfoImpl.h" #include "TargetInfo.h" +#include "clang/Basic/DiagnosticFrontend.h" using namespace clang; using namespace clang::CodeGen; @@ -145,6 +146,9 @@ public: bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; + + void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const override; }; } // namespace @@ -265,6 +269,61 @@ bool AIXTargetCodeGenInfo::initDwarfEHRegSizeTable( return PPC_initDwarfEHRegSizeTable(CGF, Address, Is64Bit, /*IsAIX*/ true); } +void AIXTargetCodeGenInfo::setTargetAttributes( + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { + if (!isa<llvm::GlobalVariable>(GV)) + return; + + auto *GVar = dyn_cast<llvm::GlobalVariable>(GV); + auto GVId = GV->getName(); + + // Is this a global variable specified by the user as toc-data? + bool UserSpecifiedTOC = + llvm::binary_search(M.getCodeGenOpts().TocDataVarsUserSpecified, GVId); + // Assumes the same variable cannot be in both TocVarsUserSpecified and + // NoTocVars. + if (UserSpecifiedTOC || + ((M.getCodeGenOpts().AllTocData) && + !llvm::binary_search(M.getCodeGenOpts().NoTocDataVars, GVId))) { + const unsigned long PointerSize = + GV->getParent()->getDataLayout().getPointerSizeInBits() / 8; + auto *VarD = dyn_cast<VarDecl>(D); + assert(VarD && "Invalid declaration of global variable."); + + ASTContext &Context = D->getASTContext(); + unsigned Alignment = Context.toBits(Context.getDeclAlign(D)) / 8; + const auto *Ty = VarD->getType().getTypePtr(); + const RecordDecl *RDecl = + Ty->isRecordType() ? Ty->getAs<RecordType>()->getDecl() : nullptr; + + bool EmitDiagnostic = UserSpecifiedTOC && GV->hasExternalLinkage(); + auto reportUnsupportedWarning = [&](bool ShouldEmitWarning, StringRef Msg) { + if (ShouldEmitWarning) + M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type) + << GVId << Msg; + }; + if (!Ty || Ty->isIncompleteType()) + reportUnsupportedWarning(EmitDiagnostic, "of incomplete type"); + else if (RDecl && RDecl->hasFlexibleArrayMember()) + reportUnsupportedWarning(EmitDiagnostic, + "it contains a flexible array member"); + else if (VarD->getTLSKind() != VarDecl::TLS_None) + reportUnsupportedWarning(EmitDiagnostic, "of thread local storage"); + else if (PointerSize < Context.getTypeInfo(VarD->getType()).Width / 8) + reportUnsupportedWarning(EmitDiagnostic, + "variable is larger than a pointer"); + else if (PointerSize < Alignment) + reportUnsupportedWarning(EmitDiagnostic, + "variable is aligned wider than a pointer"); + else if (D->hasAttr<SectionAttr>()) + reportUnsupportedWarning(EmitDiagnostic, + "variable has a section attribute"); + else if (GV->hasExternalLinkage() || + (M.getCodeGenOpts().AllTocData && !GV->hasLocalLinkage())) + GVar->addAttribute("toc-data"); + } +} + // PowerPC-32 namespace { /// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information. diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index 3c7049a..6e08990 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -433,6 +433,88 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm_unreachable("Unexpected C++ library type; only libc++ is supported."); } +// This function processes all the mtocdata options to build the final +// simplified toc data options to pass to CC1. +static void addTocDataOptions(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CC1Args, + const Driver &D) { + + // Check the global toc-data setting. The default is -mno-tocdata. + // To enable toc-data globally, -mtocdata must be specified. + // Additionally, it must be last to take effect. + const bool TOCDataGloballyinEffect = [&Args]() { + if (const Arg *LastArg = + Args.getLastArg(options::OPT_mtocdata, options::OPT_mno_tocdata)) + return LastArg->getOption().matches(options::OPT_mtocdata); + else + return false; + }(); + + // Currently only supported for small code model. + if (TOCDataGloballyinEffect && + (Args.getLastArgValue(options::OPT_mcmodel_EQ).equals("large") || + Args.getLastArgValue(options::OPT_mcmodel_EQ).equals("medium"))) { + D.Diag(clang::diag::warn_drv_unsupported_tocdata); + return; + } + + enum TOCDataSetting { + AddressInTOC = 0, // Address of the symbol stored in the TOC. + DataInTOC = 1 // Symbol defined in the TOC. + }; + + const TOCDataSetting DefaultTocDataSetting = + TOCDataGloballyinEffect ? DataInTOC : AddressInTOC; + + // Process the list of variables in the explicitly specified options + // -mtocdata= and -mno-tocdata= to see which variables are opposite to + // the global setting of tocdata in TOCDataGloballyinEffect. + // Those that have the opposite setting to TOCDataGloballyinEffect, are added + // to ExplicitlySpecifiedGlobals. + llvm::StringSet<> ExplicitlySpecifiedGlobals; + for (const auto Arg : + Args.filtered(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ)) { + TOCDataSetting ArgTocDataSetting = + Arg->getOption().matches(options::OPT_mtocdata_EQ) ? DataInTOC + : AddressInTOC; + + if (ArgTocDataSetting != DefaultTocDataSetting) + for (const char *Val : Arg->getValues()) + ExplicitlySpecifiedGlobals.insert(Val); + else + for (const char *Val : Arg->getValues()) + ExplicitlySpecifiedGlobals.erase(Val); + } + + auto buildExceptionList = [](const llvm::StringSet<> &ExplicitValues, + const char *OptionSpelling) { + std::string Option(OptionSpelling); + bool IsFirst = true; + for (const auto &E : ExplicitValues) { + if (!IsFirst) + Option += ","; + + IsFirst = false; + Option += E.first(); + } + return Option; + }; + + // Pass the final tocdata options to CC1 consisting of the default + // tocdata option (-mtocdata/-mno-tocdata) along with the list + // option (-mno-tocdata=/-mtocdata=) if there are any explicitly specified + // variables which would be exceptions to the default setting. + const char *TocDataGlobalOption = + TOCDataGloballyinEffect ? "-mtocdata" : "-mno-tocdata"; + CC1Args.push_back(TocDataGlobalOption); + + const char *TocDataListOption = + TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata="; + if (!ExplicitlySpecifiedGlobals.empty()) + CC1Args.push_back(Args.MakeArgString(llvm::Twine( + buildExceptionList(ExplicitlySpecifiedGlobals, TocDataListOption)))); +} + void AIX::addClangTargetOptions( const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const { @@ -440,6 +522,11 @@ void AIX::addClangTargetOptions( Args.AddLastArg(CC1Args, options::OPT_mdefault_visibility_export_mapping_EQ); Args.addOptInFlag(CC1Args, options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr); + // Forward last mtocdata/mno_tocdata options to -cc1. + if (Args.hasArg(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ, + options::OPT_mtocdata)) + addTocDataOptions(Args, CC1Args, getDriver()); + if (Args.hasFlag(options::OPT_fxl_pragma_pack, options::OPT_fno_xl_pragma_pack, true)) CC1Args.push_back("-fxl-pragma-pack"); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index ec4e682..019f847 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1047,6 +1047,11 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { if (getFrontendOpts().ShowStats || !getFrontendOpts().StatsFile.empty()) llvm::EnableStatistics(false); + // Sort vectors containing toc data and no toc data variables to facilitate + // binary search later. + llvm::sort(getCodeGenOpts().TocDataVarsUserSpecified); + llvm::sort(getCodeGenOpts().NoTocDataVars); + for (const FrontendInputFile &FIF : getFrontendOpts().Inputs) { // Reset the ID tables if we are reusing the SourceManager and parsing // regular files. diff --git a/clang/lib/Headers/__stddef_null.h b/clang/lib/Headers/__stddef_null.h index 7336fda..c10bd2d 100644 --- a/clang/lib/Headers/__stddef_null.h +++ b/clang/lib/Headers/__stddef_null.h @@ -7,7 +7,7 @@ *===-----------------------------------------------------------------------=== */ -#if !defined(NULL) || !__has_feature(modules) +#if !defined(NULL) || !__building_module(_Builtin_stddef) /* linux/stddef.h will define NULL to 0. glibc (and other) headers then define * __need_NULL and rely on stddef.h to redefine NULL to the correct value again. diff --git a/clang/lib/Headers/__stddef_nullptr_t.h b/clang/lib/Headers/__stddef_nullptr_t.h index 183d394..7f3fbe6 100644 --- a/clang/lib/Headers/__stddef_nullptr_t.h +++ b/clang/lib/Headers/__stddef_nullptr_t.h @@ -7,7 +7,12 @@ *===-----------------------------------------------------------------------=== */ -#ifndef _NULLPTR_T +/* + * When -fbuiltin-headers-in-system-modules is set this is a non-modular header + * and needs to behave as if it was textual. + */ +#if !defined(_NULLPTR_T) || \ + (__has_feature(modules) && !__building_module(_Builtin_stddef)) #define _NULLPTR_T #ifdef __cplusplus diff --git a/clang/lib/Headers/__stddef_offsetof.h b/clang/lib/Headers/__stddef_offsetof.h index 3b347b3..84172c6 100644 --- a/clang/lib/Headers/__stddef_offsetof.h +++ b/clang/lib/Headers/__stddef_offsetof.h @@ -7,6 +7,11 @@ *===-----------------------------------------------------------------------=== */ -#ifndef offsetof +/* + * When -fbuiltin-headers-in-system-modules is set this is a non-modular header + * and needs to behave as if it was textual. + */ +#if !defined(offsetof) || \ + (__has_feature(modules) && !__building_module(_Builtin_stddef)) #define offsetof(t, d) __builtin_offsetof(t, d) #endif diff --git a/clang/lib/Headers/__stddef_ptrdiff_t.h b/clang/lib/Headers/__stddef_ptrdiff_t.h index 3ea6d7d..fd3c893 100644 --- a/clang/lib/Headers/__stddef_ptrdiff_t.h +++ b/clang/lib/Headers/__stddef_ptrdiff_t.h @@ -7,7 +7,12 @@ *===-----------------------------------------------------------------------=== */ -#ifndef _PTRDIFF_T +/* + * When -fbuiltin-headers-in-system-modules is set this is a non-modular header + * and needs to behave as if it was textual. + */ +#if !defined(_PTRDIFF_T) || \ + (__has_feature(modules) && !__building_module(_Builtin_stddef)) #define _PTRDIFF_T typedef __PTRDIFF_TYPE__ ptrdiff_t; diff --git a/clang/lib/Headers/__stddef_rsize_t.h b/clang/lib/Headers/__stddef_rsize_t.h index b6428d0..dd433d4 100644 --- a/clang/lib/Headers/__stddef_rsize_t.h +++ b/clang/lib/Headers/__stddef_rsize_t.h @@ -7,7 +7,12 @@ *===-----------------------------------------------------------------------=== */ -#ifndef _RSIZE_T +/* + * When -fbuiltin-headers-in-system-modules is set this is a non-modular header + * and needs to behave as if it was textual. + */ +#if !defined(_RSIZE_T) || \ + (__has_feature(modules) && !__building_module(_Builtin_stddef)) #define _RSIZE_T typedef __SIZE_TYPE__ rsize_t; diff --git a/clang/lib/Headers/__stddef_size_t.h b/clang/lib/Headers/__stddef_size_t.h index e4a3895..3dd7b1f 100644 --- a/clang/lib/Headers/__stddef_size_t.h +++ b/clang/lib/Headers/__stddef_size_t.h @@ -7,7 +7,12 @@ *===-----------------------------------------------------------------------=== */ -#ifndef _SIZE_T +/* + * When -fbuiltin-headers-in-system-modules is set this is a non-modular header + * and needs to behave as if it was textual. + */ +#if !defined(_SIZE_T) || \ + (__has_feature(modules) && !__building_module(_Builtin_stddef)) #define _SIZE_T typedef __SIZE_TYPE__ size_t; diff --git a/clang/lib/Headers/__stddef_unreachable.h b/clang/lib/Headers/__stddef_unreachable.h index 3e7fe01..518580c 100644 --- a/clang/lib/Headers/__stddef_unreachable.h +++ b/clang/lib/Headers/__stddef_unreachable.h @@ -7,6 +7,11 @@ *===-----------------------------------------------------------------------=== */ -#ifndef unreachable +/* + * When -fbuiltin-headers-in-system-modules is set this is a non-modular header + * and needs to behave as if it was textual. + */ +#if !defined(unreachable) || \ + (__has_feature(modules) && !__building_module(_Builtin_stddef)) #define unreachable() __builtin_unreachable() #endif diff --git a/clang/lib/Headers/__stddef_wchar_t.h b/clang/lib/Headers/__stddef_wchar_t.h index 16a6186..bd69f63 100644 --- a/clang/lib/Headers/__stddef_wchar_t.h +++ b/clang/lib/Headers/__stddef_wchar_t.h @@ -9,7 +9,12 @@ #if !defined(__cplusplus) || (defined(_MSC_VER) && !_NATIVE_WCHAR_T_DEFINED) -#ifndef _WCHAR_T +/* + * When -fbuiltin-headers-in-system-modules is set this is a non-modular header + * and needs to behave as if it was textual. + */ +#if !defined(_WCHAR_T) || \ + (__has_feature(modules) && !__building_module(_Builtin_stddef)) #define _WCHAR_T #ifdef _MSC_EXTENSIONS diff --git a/clang/lib/Headers/module.modulemap b/clang/lib/Headers/module.modulemap index a786689..56a13f6 100644 --- a/clang/lib/Headers/module.modulemap +++ b/clang/lib/Headers/module.modulemap @@ -155,9 +155,9 @@ module _Builtin_intrinsics [system] [extern_c] { // Start -fbuiltin-headers-in-system-modules affected modules -// The following modules all ignore their top level headers -// when -fbuiltin-headers-in-system-modules is passed, and -// most of those headers join system modules when present. +// The following modules all ignore their headers when +// -fbuiltin-headers-in-system-modules is passed, and many of +// those headers join system modules when present. // e.g. if -fbuiltin-headers-in-system-modules is passed, then // float.h will not be in the _Builtin_float module (that module @@ -190,11 +190,6 @@ module _Builtin_stdalign [system] { export * } -// When -fbuiltin-headers-in-system-modules is passed, only -// the top level headers are removed, the implementation headers -// will always be in their submodules. That means when stdarg.h -// is included, it will still import this module and make the -// appropriate submodules visible. module _Builtin_stdarg [system] { textual header "stdarg.h" @@ -237,6 +232,8 @@ module _Builtin_stdbool [system] { module _Builtin_stddef [system] { textual header "stddef.h" + // __stddef_max_align_t.h is always in this module, even if + // -fbuiltin-headers-in-system-modules is passed. explicit module max_align_t { header "__stddef_max_align_t.h" export * @@ -283,9 +280,10 @@ module _Builtin_stddef [system] { } } -/* wint_t is provided by <wchar.h> and not <stddef.h>. It's here - * for compatibility, but must be explicitly requested. Therefore - * __stddef_wint_t.h is not part of _Builtin_stddef. */ +// wint_t is provided by <wchar.h> and not <stddef.h>. It's here +// for compatibility, but must be explicitly requested. Therefore +// __stddef_wint_t.h is not part of _Builtin_stddef. It is always in +// this module even if -fbuiltin-headers-in-system-modules is passed. module _Builtin_stddef_wint_t [system] { header "__stddef_wint_t.h" export * diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index afb2948..10c475f 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -2498,9 +2498,12 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, } bool NeedsFramework = false; - // Don't add the top level headers to the builtin modules if the builtin headers - // belong to the system modules. - if (!Map.LangOpts.BuiltinHeadersInSystemModules || ActiveModule->isSubModule() || !isBuiltInModuleName(ActiveModule->Name)) + // Don't add headers to the builtin modules if the builtin headers belong to + // the system modules, with the exception of __stddef_max_align_t.h which + // always had its own module. + if (!Map.LangOpts.BuiltinHeadersInSystemModules || + !isBuiltInModuleName(ActiveModule->getTopLevelModuleName()) || + ActiveModule->fullModuleNameIs({"_Builtin_stddef", "max_align_t"})) Map.addUnresolvedHeader(ActiveModule, std::move(Header), NeedsFramework); if (NeedsFramework) diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 1701d15..cc0e41e 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -685,7 +685,7 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, // FIXME: We need a better way to disambiguate C++ clang modules and // standard C++ modules. if (!getLangOpts().CPlusPlusModules || !Mod->isHeaderUnit()) - Actions.ActOnModuleInclude(Loc, Mod); + Actions.ActOnAnnotModuleInclude(Loc, Mod); else { DeclResult Import = Actions.ActOnModuleImport(Loc, SourceLocation(), Loc, Mod); @@ -697,15 +697,17 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, } case tok::annot_module_begin: - Actions.ActOnModuleBegin(Tok.getLocation(), reinterpret_cast<Module *>( - Tok.getAnnotationValue())); + Actions.ActOnAnnotModuleBegin( + Tok.getLocation(), + reinterpret_cast<Module *>(Tok.getAnnotationValue())); ConsumeAnnotationToken(); ImportState = Sema::ModuleImportState::NotACXX20Module; return false; case tok::annot_module_end: - Actions.ActOnModuleEnd(Tok.getLocation(), reinterpret_cast<Module *>( - Tok.getAnnotationValue())); + Actions.ActOnAnnotModuleEnd( + Tok.getLocation(), + reinterpret_cast<Module *>(Tok.getAnnotationValue())); ConsumeAnnotationToken(); ImportState = Sema::ModuleImportState::NotACXX20Module; return false; @@ -2708,9 +2710,9 @@ bool Parser::parseMisplacedModuleImport() { // happens. if (MisplacedModuleBeginCount) { --MisplacedModuleBeginCount; - Actions.ActOnModuleEnd(Tok.getLocation(), - reinterpret_cast<Module *>( - Tok.getAnnotationValue())); + Actions.ActOnAnnotModuleEnd( + Tok.getLocation(), + reinterpret_cast<Module *>(Tok.getAnnotationValue())); ConsumeAnnotationToken(); continue; } @@ -2720,18 +2722,18 @@ bool Parser::parseMisplacedModuleImport() { return true; case tok::annot_module_begin: // Recover by entering the module (Sema will diagnose). - Actions.ActOnModuleBegin(Tok.getLocation(), - reinterpret_cast<Module *>( - Tok.getAnnotationValue())); + Actions.ActOnAnnotModuleBegin( + Tok.getLocation(), + reinterpret_cast<Module *>(Tok.getAnnotationValue())); ConsumeAnnotationToken(); ++MisplacedModuleBeginCount; continue; case tok::annot_module_include: // Module import found where it should not be, for instance, inside a // namespace. Recover by importing the module. - Actions.ActOnModuleInclude(Tok.getLocation(), - reinterpret_cast<Module *>( - Tok.getAnnotationValue())); + Actions.ActOnAnnotModuleInclude( + Tok.getLocation(), + reinterpret_cast<Module *>(Tok.getAnnotationValue())); ConsumeAnnotationToken(); // If there is another module import, process it. continue; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 720d5fd..cd0c42d 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1207,26 +1207,35 @@ void Sema::ActOnEndOfTranslationUnit() { } // A global-module-fragment is only permitted within a module unit. - bool DiagnosedMissingModuleDeclaration = false; if (!ModuleScopes.empty() && ModuleScopes.back().Module->Kind == Module::ExplicitGlobalModuleFragment) { Diag(ModuleScopes.back().BeginLoc, diag::err_module_declaration_missing_after_global_module_introducer); - DiagnosedMissingModuleDeclaration = true; - } - - if (TUKind == TU_Module) { - // If we are building a module interface unit, we need to have seen the - // module declaration by now. - if (getLangOpts().getCompilingModule() == - LangOptions::CMK_ModuleInterface && - !isCurrentModulePurview() && !DiagnosedMissingModuleDeclaration) { - // FIXME: Make a better guess as to where to put the module declaration. - Diag(getSourceManager().getLocForStartOfFile( - getSourceManager().getMainFileID()), - diag::err_module_declaration_missing); - } + } + + // Now we can decide whether the modules we're building need an initializer. + if (Module *CurrentModule = getCurrentModule(); + CurrentModule && CurrentModule->isInterfaceOrPartition()) { + auto DoesModNeedInit = [this](Module *M) { + if (!getASTContext().getModuleInitializers(M).empty()) + return true; + for (auto [Exported, _] : M->Exports) + if (Exported->isNamedModuleInterfaceHasInit()) + return true; + for (Module *I : M->Imports) + if (I->isNamedModuleInterfaceHasInit()) + return true; + + return false; + }; + CurrentModule->NamedModuleHasInit = + DoesModNeedInit(CurrentModule) || + llvm::any_of(CurrentModule->submodules(), + [&](auto *SubM) { return DoesModNeedInit(SubM); }); + } + + if (TUKind == TU_ClangModule) { // If we are building a module, resolve all of the exported declarations // now. if (Module *CurrentModule = PP.getCurrentModule()) { @@ -1251,28 +1260,6 @@ void Sema::ActOnEndOfTranslationUnit() { } } - // Now we can decide whether the modules we're building need an initializer. - if (Module *CurrentModule = getCurrentModule(); - CurrentModule && CurrentModule->isInterfaceOrPartition()) { - auto DoesModNeedInit = [this](Module *M) { - if (!getASTContext().getModuleInitializers(M).empty()) - return true; - for (auto [Exported, _] : M->Exports) - if (Exported->isNamedModuleInterfaceHasInit()) - return true; - for (Module *I : M->Imports) - if (I->isNamedModuleInterfaceHasInit()) - return true; - - return false; - }; - - CurrentModule->NamedModuleHasInit = - DoesModNeedInit(CurrentModule) || - llvm::any_of(CurrentModule->submodules(), - [&](auto *SubM) { return DoesModNeedInit(SubM); }); - } - // Warnings emitted in ActOnEndOfTranslationUnit() should be emitted for // modules when they are built, not every time they are used. emitAndClearUnusedLocalTypedefWarnings(); @@ -1358,7 +1345,7 @@ void Sema::ActOnEndOfTranslationUnit() { // noise. Don't warn for a use from a module: either we should warn on all // file-scope declarations in modules or not at all, but whether the // declaration is used is immaterial. - if (!Diags.hasErrorOccurred() && TUKind != TU_Module) { + if (!Diags.hasErrorOccurred() && TUKind != TU_ClangModule) { // Output warning for unused file scoped decls. for (UnusedFileScopedDeclsType::iterator I = UnusedFileScopedDecls.begin(ExternalSource.get()), diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index e3da3e6..ec00fdf 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3787,6 +3787,30 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) { << NI.getName() << ParamTy << Ty; return; } + VarDecl *VD = cast<VarDecl>(D); + // Create a reference to the variable declaration. This is a fake/dummy + // reference. + DeclRefExpr *VariableReference = DeclRefExpr::Create( + S.Context, NestedNameSpecifierLoc{}, FD->getLocation(), VD, false, + DeclarationNameInfo{VD->getDeclName(), VD->getLocation()}, VD->getType(), + VK_LValue); + + // Create a unary operator expression that represents taking the address of + // the variable. This is a fake/dummy expression. + Expr *AddressOfVariable = UnaryOperator::Create( + S.Context, VariableReference, UnaryOperatorKind::UO_AddrOf, + S.Context.getPointerType(VD->getType()), VK_PRValue, OK_Ordinary, Loc, + +false, FPOptionsOverride{}); + + // Create a function call expression. This is a fake/dummy call expression. + CallExpr *FunctionCallExpression = + CallExpr::Create(S.Context, E, ArrayRef{AddressOfVariable}, + S.Context.VoidTy, VK_PRValue, Loc, FPOptionsOverride{}); + + if (S.CheckFunctionCall(FD, FunctionCallExpression, + FD->getType()->getAs<FunctionProtoType>())) { + return; + } D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD)); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 93f82e6..8725b09 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1099,12 +1099,13 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return E; } -/// Converts an integer to complex float type. Helper function of +/// Convert complex integers to complex floats and real integers to +/// real floats as required for complex arithmetic. Helper function of /// UsualArithmeticConversions() /// /// \return false if the integer expression is an integer type and is -/// successfully converted to the complex type. -static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, +/// successfully converted to the (complex) float type. +static bool handleComplexIntegerToFloatConversion(Sema &S, ExprResult &IntExpr, ExprResult &ComplexExpr, QualType IntTy, QualType ComplexTy, @@ -1114,8 +1115,6 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, if (IntTy->isIntegerType()) { QualType fpTy = ComplexTy->castAs<ComplexType>()->getElementType(); IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating); - IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy, - CK_FloatingRealToComplex); } else { assert(IntTy->isComplexIntegerType()); IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy, @@ -1160,11 +1159,11 @@ static QualType handleComplexFloatConversion(Sema &S, ExprResult &Shorter, static QualType handleComplexConversion(Sema &S, ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, bool IsCompAssign) { - // if we have an integer operand, the result is the complex type. - if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType, + // Handle (complex) integer types. + if (!handleComplexIntegerToFloatConversion(S, RHS, LHS, RHSType, LHSType, /*SkipCast=*/false)) return LHSType; - if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType, + if (!handleComplexIntegerToFloatConversion(S, LHS, RHS, LHSType, RHSType, /*SkipCast=*/IsCompAssign)) return RHSType; diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index f08c1cb3..2ddf9d7 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -713,7 +713,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, return Import; } -void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { +void Sema::ActOnAnnotModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true); BuildModuleInclude(DirectiveLoc, Mod); } @@ -723,9 +723,9 @@ void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { // in that buffer do not qualify as module imports; they're just an // implementation detail of us building the module. // - // FIXME: Should we even get ActOnModuleInclude calls for those? + // FIXME: Should we even get ActOnAnnotModuleInclude calls for those? bool IsInModuleIncludes = - TUKind == TU_Module && + TUKind == TU_ClangModule && getSourceManager().isWrittenInMainFile(DirectiveLoc); // If we are really importing a module (not just checking layering) due to an @@ -752,7 +752,7 @@ void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { } } -void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) { +void Sema::ActOnAnnotModuleBegin(SourceLocation DirectiveLoc, Module *Mod) { checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true); ModuleScopes.push_back({}); @@ -776,7 +776,7 @@ void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) { } } -void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) { +void Sema::ActOnAnnotModuleEnd(SourceLocation EomLoc, Module *Mod) { if (getLangOpts().ModulesLocalVisibility) { VisibleModules = std::move(ModuleScopes.back().OuterVisibleModules); // Leaving a module hides namespace names, so our visible namespace cache diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index d8c9a5c..51e8db2 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2906,18 +2906,27 @@ void DeclareImplicitDeductionGuidesForTypeAlias( Context.getCanonicalTemplateArgument( Context.getInjectedTemplateArg(NewParam)); } - // FIXME: implement the associated constraint per C++ + // Substitute new template parameters into requires-clause if present. + Expr *RequiresClause = nullptr; + if (Expr *InnerRC = F->getTemplateParameters()->getRequiresClause()) { + MultiLevelTemplateArgumentList Args; + Args.setKind(TemplateSubstitutionKind::Rewrite); + Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime); + ExprResult E = SemaRef.SubstExpr(InnerRC, Args); + if (E.isInvalid()) + return; + RequiresClause = E.getAs<Expr>(); + } + // FIXME: implement the is_deducible constraint per C++ // [over.match.class.deduct]p3.3: - // The associated constraints ([temp.constr.decl]) are the - // conjunction of the associated constraints of g and a - // constraint that is satisfied if and only if the arguments + // ... and a constraint that is satisfied if and only if the arguments // of A are deducible (see below) from the return type. auto *FPrimeTemplateParamList = TemplateParameterList::Create( Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(), AliasTemplate->getTemplateParameters()->getLAngleLoc(), FPrimeTemplateParams, AliasTemplate->getTemplateParameters()->getRAngleLoc(), - /*RequiresClause=*/nullptr); + /*RequiresClause=*/RequiresClause); // To form a deduction guide f' from f, we leverage clang's instantiation // mechanism, we construct a template argument list where the template |