llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: purnima shrivastava (purnima-nlp) <details> <summary>Changes</summary> This PR addresses a compiler crash encountered when handling defaulted comparison operators (`operator<=>`) inside a struct. - Explored the Clang AST and Sema codebase (`clang/lib/AST/Decl.cpp` and `clang/lib/Sema/SemaDeclCXX.cpp`) to trace and resolve the underlying recovery state handling, added some code too in these files. - Added a new regression test (`clang/test/SemaCXX/defaulted-compare-recovery-crash.cpp`) to ensure the compiler recovers cleanly and emits proper diagnostics instead of crashing. - issue #<!-- -->210286 --- Patch is 277.70 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/210668.diff 3 Files Affected: - (modified) clang/lib/AST/Decl.cpp (+241-251) - (modified) clang/lib/Sema/SemaDeclCXX.cpp (+1150-1237) - (added) clang/test/SemaCXX/defaulted-compare-recovery-crash.cpp (+16) ``````````diff diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 4eaef0d87f3e5..825244d79973d 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -79,7 +79,8 @@ Decl *clang::getPrimaryMergedDecl(Decl *D) { void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const { SourceLocation Loc = this->Loc; - if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation(); + if (!Loc.isValid() && TheDecl) + Loc = TheDecl->getLocation(); if (Loc.isValid()) { Loc.print(OS, Context.getSourceManager()); OS << ": "; @@ -162,8 +163,7 @@ static bool hasExplicitVisibilityAlready(LVComputationKind computation) { /// Given an LVComputationKind, return one of the same type/value sort /// that records that it already has explicit visibility. -static LVComputationKind -withExplicitVisibilityAlready(LVComputationKind Kind) { +static LVComputationKind withExplicitVisibilityAlready(LVComputationKind Kind) { Kind.IgnoreExplicitVisibility = true; return Kind; } @@ -178,8 +178,7 @@ static std::optional<Visibility> getExplicitVisibility(const NamedDecl *D, /// Is the given declaration a "type" or a "value" for the purposes of /// visibility computation? static bool usesTypeVisibility(const NamedDecl *D) { - return isa<TypeDecl>(D) || - isa<ClassTemplateDecl>(D) || + return isa<TypeDecl>(D) || isa<ClassTemplateDecl>(D) || isa<ObjCInterfaceDecl>(D); } @@ -189,7 +188,7 @@ template <class T> static std::enable_if_t<!std::is_base_of_v<RedeclarableTemplateDecl, T>, bool> isExplicitMemberSpecialization(const T *D) { if (const MemberSpecializationInfo *member = - D->getMemberSpecializationInfo()) { + D->getMemberSpecializationInfo()) { return member->isExplicitSpecialization(); } return false; @@ -204,8 +203,7 @@ static bool isExplicitMemberSpecialization(const RedeclarableTemplateDecl *D) { /// Given a visibility attribute, return the explicit visibility /// associated with it. -template <class T> -static Visibility getVisibilityFromAttr(const T *attr) { +template <class T> static Visibility getVisibilityFromAttr(const T *attr) { switch (attr->getVisibility()) { case T::Default: return DefaultVisibility; @@ -289,8 +287,8 @@ LinkageInfo LinkageComputer::getLVForTemplateParameterList( } // Look at all expansions in an expanded pack. - for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters(); - i != n; ++i) { + for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters(); i != n; + ++i) { LV.merge(getLVForTemplateParameterList( TTP->getExpansionTemplateParameters(i), computation)); } @@ -370,8 +368,9 @@ LinkageComputer::getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, return getLVForTemplateArgumentList(TArgs.asArray(), computation); } -static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn, - const FunctionTemplateSpecializationInfo *specInfo) { +static bool shouldConsiderTemplateVisibility( + const FunctionDecl *fn, + const FunctionTemplateSpecializationInfo *specInfo) { // Include visibility from the template parameters and arguments // only if this is not an explicit instantiation or specialization // with direct explicit visibility. (Implicit instantiations won't @@ -393,8 +392,7 @@ void LinkageComputer::mergeTemplateLV( LinkageInfo &LV, const FunctionDecl *fn, const FunctionTemplateSpecializationInfo *specInfo, LVComputationKind computation) { - bool considerVisibility = - shouldConsiderTemplateVisibility(fn, specInfo); + bool considerVisibility = shouldConsiderTemplateVisibility(fn, specInfo); FunctionTemplateDecl *temp = specInfo->getTemplate(); // Merge information from the template declaration. @@ -427,8 +425,8 @@ static bool hasDirectVisibilityAttribute(const NamedDecl *D, /// Should we consider visibility associated with the template /// arguments and parameters of the given class template specialization? -static bool shouldConsiderTemplateVisibility( - const ClassTemplateSpecializationDecl *spec, +static bool +shouldConsiderTemplateVisibility(const ClassTemplateSpecializationDecl *spec, LVComputationKind computation) { // Include visibility from the template parameters and arguments // only if this is not an explicit instantiation or specialization @@ -478,9 +476,10 @@ void LinkageComputer::mergeTemplateLV( LV.setLinkage(tempLV.getLinkage()); LinkageInfo paramsLV = - getLVForTemplateParameterList(temp->getTemplateParameters(), computation); + getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(paramsLV, - considerVisibility && !hasExplicitVisibilityAlready(computation)); + considerVisibility && + !hasExplicitVisibilityAlready(computation)); // Merge information from the template arguments. We ignore // template-argument visibility if we've got an explicit @@ -496,8 +495,8 @@ void LinkageComputer::mergeTemplateLV( /// arguments and parameters of the given variable template /// specialization? As usual, follow class template specialization /// logic up to initialization. -static bool shouldConsiderTemplateVisibility( - const VarTemplateSpecializationDecl *spec, +static bool +shouldConsiderTemplateVisibility(const VarTemplateSpecializationDecl *spec, LVComputationKind computation) { // Include visibility from the template parameters and arguments // only if this is not an explicit instantiation or specialization @@ -529,9 +528,9 @@ void LinkageComputer::mergeTemplateLV(LinkageInfo &LV, // visibility if we're only considering template arguments. VarTemplateDecl *temp = spec->getSpecializedTemplate(); LinkageInfo tempLV = - getLVForTemplateParameterList(temp->getTemplateParameters(), computation); - LV.mergeMaybeWithVisibility(tempLV, - considerVisibility && !hasExplicitVisibilityAlready(computation)); + getLVForTemplateParameterList(temp->getTemplateParameters(), computation); + LV.mergeMaybeWithVisibility( + tempLV, considerVisibility && !hasExplicitVisibilityAlready(computation)); // Merge information from the template arguments. We ignore // template-argument visibility if we've got an explicit @@ -554,11 +553,11 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) { return false; TemplateSpecializationKind TSK = TSK_Undeclared; - if (FunctionTemplateSpecializationInfo *spec - = FD->getTemplateSpecializationInfo()) { + if (FunctionTemplateSpecializationInfo *spec = + FD->getTemplateSpecializationInfo()) { TSK = spec->getTemplateSpecializationKind(); } else if (MemberSpecializationInfo *MSI = - FD->getMemberSpecializationInfo()) { + FD->getMemberSpecializationInfo()) { TSK = MSI->getTemplateSpecializationKind(); } @@ -567,8 +566,8 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) { // isInlined() only gives meaningful answers on definitions // anyway. return TSK != TSK_ExplicitInstantiationDeclaration && - TSK != TSK_ExplicitInstantiationDefinition && - FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>(); + TSK != TSK_ExplicitInstantiationDefinition && FD->hasBody(Def) && + Def->isInlined() && !Def->hasAttr<GNUInlineAttr>(); } template <typename T> static bool isFirstInExternCContext(T *D) { @@ -704,10 +703,10 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, // If we're declared in a namespace with a visibility attribute, // use that namespace's visibility, and it still counts as explicit. for (const DeclContext *DC = D->getDeclContext(); - !isa<TranslationUnitDecl>(DC); - DC = DC->getParent()) { + !isa<TranslationUnitDecl>(DC); DC = DC->getParent()) { const auto *ND = dyn_cast<NamespaceDecl>(DC); - if (!ND) continue; + if (!ND) + continue; if (std::optional<Visibility> Vis = getExplicitVisibility(ND, computation)) { LV.mergeVisibility(*Vis, true); @@ -794,7 +793,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, mergeTemplateLV(LV, spec, computation); } - // - a function; or + // - a function; or } else if (const auto *Function = dyn_cast<FunctionDecl>(D)) { // In theory, we can modify the function's LV by the LV of its // type unless it has C linkage (see comment above about variables @@ -834,17 +833,17 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, // Consider LV from the template and the template arguments. // We're at file scope, so we do not need to worry about nested // specializations. - if (FunctionTemplateSpecializationInfo *specInfo - = Function->getTemplateSpecializationInfo()) { + if (FunctionTemplateSpecializationInfo *specInfo = + Function->getTemplateSpecializationInfo()) { mergeTemplateLV(LV, Function, specInfo, computation); } - // - a named class (Clause 9), or an unnamed class defined in a - // typedef declaration in which the class has the typedef name - // for linkage purposes (7.1.3); or - // - a named enumeration (7.2), or an unnamed enumeration - // defined in a typedef declaration in which the enumeration - // has the typedef name for linkage purposes (7.1.3); or + // - a named class (Clause 9), or an unnamed class defined in a + // typedef declaration in which the class has the typedef name + // for linkage purposes (7.1.3); or + // - a named enumeration (7.2), or an unnamed enumeration + // defined in a typedef declaration in which the enumeration + // has the typedef name for linkage purposes (7.1.3); or } else if (const auto *Tag = dyn_cast<TagDecl>(D)) { // Unnamed tags have no linkage. if (!Tag->hasNameForLinkage()) @@ -857,46 +856,46 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, mergeTemplateLV(LV, spec, computation); } - // FIXME: This is not part of the C++ standard any more. - // - an enumerator belonging to an enumeration with external linkage; or + // FIXME: This is not part of the C++ standard any more. + // - an enumerator belonging to an enumeration with external linkage; or } else if (isa<EnumConstantDecl>(D)) { - LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), - computation); + LinkageInfo EnumLV = + getLVForDecl(cast<NamedDecl>(D->getDeclContext()), computation); if (!isExternalFormalLinkage(EnumLV.getLinkage())) return LinkageInfo::none(); LV.merge(EnumLV); - // - a template + // - a template } else if (const auto *temp = dyn_cast<TemplateDecl>(D)) { bool considerVisibility = !hasExplicitVisibilityAlready(computation); - LinkageInfo tempLV = - getLVForTemplateParameterList(temp->getTemplateParameters(), computation); + LinkageInfo tempLV = getLVForTemplateParameterList( + temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); - // An unnamed namespace or a namespace declared directly or indirectly - // within an unnamed namespace has internal linkage. All other namespaces - // have external linkage. - // - // We handled names in anonymous namespaces above. + // An unnamed namespace or a namespace declared directly or indirectly + // within an unnamed namespace has internal linkage. All other + // namespaces have external linkage. + // + // We handled names in anonymous namespaces above. } else if (isa<NamespaceDecl>(D)) { return LV; - // By extension, we assign external linkage to Objective-C - // interfaces. + // By extension, we assign external linkage to Objective-C + // interfaces. } else if (isa<ObjCInterfaceDecl>(D)) { // fallout } else if (auto *TD = dyn_cast<TypedefNameDecl>(D)) { // A typedef declaration has linkage if it gives a type a name for // linkage purposes. - if (!TD->getAnonDeclWithTypedefName(/*AnyRedecl*/true)) + if (!TD->getAnonDeclWithTypedefName(/*AnyRedecl*/ true)) return LinkageInfo::none(); } else if (isa<MSGuidDecl>(D)) { // A GUID behaves like an inline variable with external linkage. Fall // through. - // Everything not covered here has no linkage. + // Everything not covered here has no linkage. } else { return LinkageInfo::none(); } @@ -909,10 +908,9 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, return LV; } -LinkageInfo -LinkageComputer::getLVForClassMember(const NamedDecl *D, - LVComputationKind computation, - bool IgnoreVarTypeLinkage) { +LinkageInfo LinkageComputer::getLVForClassMember(const NamedDecl *D, + LVComputationKind computation, + bool IgnoreVarTypeLinkage) { // Only certain class members have linkage. Note that fields don't // really have linkage, but it's convenient to say they do for the // purposes of calculating linkage of pointer-to-data-member @@ -923,12 +921,8 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D, // linkage and visibility of a template specialization, we might hit // a template template argument that way. If we do, we need to // consider its linkage. - if (!(isa<CXXMethodDecl>(D) || - isa<VarDecl>(D) || - isa<FieldDecl>(D) || - isa<IndirectFieldDecl>(D) || - isa<TagDecl>(D) || - isa<TemplateDecl>(D))) + if (!(isa<CXXMethodDecl>(D) || isa<VarDecl>(D) || isa<FieldDecl>(D) || + isa<IndirectFieldDecl>(D) || isa<TagDecl>(D) || isa<TemplateDecl>(D))) return LinkageInfo::none(); LinkageInfo LV; @@ -954,14 +948,13 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D, classComputation = withExplicitVisibilityAlready(computation); LinkageInfo classLV = - getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation); + getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation); // The member has the same linkage as the class. If that's not externally // visible, we don't need to compute anything about the linkage. // FIXME: If we're only computing linkage, can we bail out here? if (!isExternallyVisible(classLV.getLinkage())) return classLV; - // Otherwise, don't merge in classLV yet, because in certain cases // we need to completely ignore the visibility from it. @@ -979,8 +972,8 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D, // If this is a method template specialization, use the linkage for // the template parameters and arguments. - if (FunctionTemplateSpecializationInfo *spec - = MD->getTemplateSpecializationInfo()) { + if (FunctionTemplateSpecializationInfo *spec = + MD->getTemplateSpecializationInfo()) { mergeTemplateLV(LV, MD, spec, computation); if (spec->isExplicitSpecialization()) { explicitSpecSuppressor = MD; @@ -1017,7 +1010,7 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D, explicitSpecSuppressor = RD; } - // Static data members. + // Static data members. } else if (const auto *VD = dyn_cast<VarDecl>(D)) { if (const auto *spec = dyn_cast<VarTemplateSpecializationDecl>(VD)) mergeTemplateLV(LV, spec, computation); @@ -1037,14 +1030,13 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D, explicitSpecSuppressor = VD; } - // Template members. + // Template members. } else if (const auto *temp = dyn_cast<TemplateDecl>(D)) { bool considerVisibility = - (!LV.isVisibilityExplicit() && - !classLV.isVisibilityExplicit() && - !hasExplicitVisibilityAlready(computation)); - LinkageInfo tempLV = - getLVForTemplateParameterList(temp->getTemplateParameters(), computation); + (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit() && + !hasExplicitVisibilityAlready(computation)); + LinkageInfo tempLV = getLVForTemplateParameterList( + temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); if (const auto *redeclTemp = dyn_cast<RedeclarableTemplateDecl>(temp)) { @@ -1168,7 +1160,8 @@ NamedDecl::isReserved(const LangOptions &LangOpts) const { ObjCStringFormatFamily NamedDecl::getObjCFStringFormattingFamily() const { StringRef name = getName(); - if (name.empty()) return SFF_None; + if (name.empty()) + return SFF_None; if (name.front() == 'C') if (name == "CFStringCreateWithFormat" || @@ -1289,8 +1282,8 @@ getExplicitVisibilityAux(const NamedDecl *ND, if (const auto *fn = dyn_cast<FunctionDecl>(ND)) { // If the function is a specialization of a template with an // explicit visibility attribute, use that. - if (FunctionTemplateSpecializationInfo *templateInfo - = fn->getTemplateSpecializationInfo()) + if (FunctionTemplateSpecializationInfo *templateInfo = + fn->getTemplateSpecializationInfo()) return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(), kind); @@ -1343,7 +1336,7 @@ LinkageInfo LinkageComputer::getLVForClosure(const DeclContext *DC, auto *VD = dyn_cast<VarDecl>(Owner); LinkageInfo OwnerLV = VD && VD->getType()->getContainedDeducedType() - ? computeLVForDecl(Owner, computation, /*IgnoreVarTypeLinkage*/true) + ? computeLVForDecl(Owner, computation, /*IgnoreVarTypeLinkage*/ true) : getLVForDecl(Owner, computation); // A lambda never formally has linkage. But if the owner is externally @@ -1467,78 +1460,77 @@ LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D, // Objective-C: treat all Objective-C declarations as having external // linkage. switch (D->getKind()) { - default: - break; + default: + break; - // Per C++ [basic.link]p2, only the names of objects, references, - // functions, types, templates, namespaces, and values ever have linkage. - // - // Note that the name of a typedef, namespace alias, using declaration, - // and so on are not the name of the corresponding type, namespace, or - // declaration, so they do *not* have linkage. - case Decl::ImplicitParam: - case Decl::Label: - case Decl::NamespaceAlias: - case Decl::ParmVar: - case Decl::Using: - case Decl::UsingEnum: - case Decl::UsingShadow: - case Decl::UsingDirective: - return LinkageInfo::none(); + // Per C++ [basic.link]p2, only the names of objects, references, + // functions, types, templates, namespaces, and values ever have linkage. + // + // Note that the name of a typedef, namespace alias, using declaration, + // and so on are not the name of the corresponding type, namespace, or + // declaration, so they do *not* have linkage. + case Decl::ImplicitParam: + case Decl::Label: + case Decl::NamespaceAlias: + case Decl::ParmVar: + case Decl::Using: + case Decl::UsingEnum: + case Decl::UsingShadow: + case Decl::UsingDirective: + return LinkageInfo::none(); - case Decl::EnumConstant: - // C++ [basic.link]p4: an enumerator has the linkage of its enumeration. - if (D->getASTContext().getLangOpts().CPlusPlus) - return getLVForDecl(cast<EnumDecl>(D->getDeclContext()), computation); - return LinkageInfo::visible_none(); - - case Decl::Typedef: - case Decl::TypeAlias: - // A typedef declaration has linkage if it gives a type a name for - // linkage purposes. - if (!cast<TypedefNameDecl>(D) - ->getAnonDeclWithTypedefName(/*AnyRedecl*/true)) - return LinkageInfo::none(); - break; + case Decl::EnumConstant: + // C++ [basic.link]p4: an enumerator has the linkage of its enumeration. + if (D->getAS... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/210668 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
