Author: gbiv Date: Tue Aug 8 21:02:49 2017 New Revision: 310436 URL: http://llvm.org/viewvc/llvm-project?rev=310436&view=rev Log: [AST] Move visibility computations into a class; NFC
This is patch 1 in a 2 patch series that aims to fix PR29160. Its goal is to cache decl visibility/linkage for the duration of each visibility+linkage query. The simplest way I can see to do this is to put the visibility calculation code that needs to (transitively) access this cache into a class, which is what this patch does. Actual caching will come in patch 2. (Another way would be to keep the cache in ASTContext + manually invalidate it or something, but that felt way too subtle to me.) Caching visibility results across multiple queries seems a bit tricky, since the user can add visibility attributes ~whenever they want, and these attributes can apparently have far-reaching effects (e.g. class visibility extends to its members, ...). Because a cache that's dropped at the end of each top-level query seems to work nearly as well and doesn't require any eviction logic, I opted for that design. Added: cfe/trunk/lib/AST/Linkage.h Modified: cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/AST/Type.cpp Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=310436&r1=310435&r2=310436&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Tue Aug 8 21:02:49 2017 @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/Decl.h" +#include "Linkage.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" @@ -99,38 +100,6 @@ TranslationUnitDecl::TranslationUnitDecl // and 'matcher' is a type only matters when looking for attributes // and settings from the immediate context. -const static unsigned IgnoreExplicitVisibilityBit = 2; -const static unsigned IgnoreAllVisibilityBit = 4; - -/// Kinds of LV computation. The linkage side of the computation is -/// always the same, but different things can change how visibility is -/// computed. -enum LVComputationKind { - /// Do an LV computation for, ultimately, a type. - /// Visibility may be restricted by type visibility settings and - /// the visibility of template arguments. - LVForType = NamedDecl::VisibilityForType, - - /// Do an LV computation for, ultimately, a non-type declaration. - /// Visibility may be restricted by value visibility settings and - /// the visibility of template arguments. - LVForValue = NamedDecl::VisibilityForValue, - - /// Do an LV computation for, ultimately, a type that already has - /// some sort of explicit visibility. Visibility may only be - /// restricted by the visibility of template arguments. - LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit), - - /// Do an LV computation for, ultimately, a non-type declaration - /// that already has some sort of explicit visibility. Visibility - /// may only be restricted by the visibility of template arguments. - LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit), - - /// Do an LV computation when we only care about the linkage. - LVForLinkageOnly = - LVForValue | IgnoreExplicitVisibilityBit | IgnoreAllVisibilityBit -}; - /// Does this computation kind permit us to consider additional /// visibility settings from attributes and the like? static bool hasExplicitVisibilityAlready(LVComputationKind computation) { @@ -219,8 +188,8 @@ static Optional<Visibility> getVisibilit return None; } -static LinkageInfo -getLVForType(const Type &T, LVComputationKind computation) { +LinkageInfo LinkageComputer::getLVForType(const Type &T, + LVComputationKind computation) { if (computation == LVForLinkageOnly) return LinkageInfo(T.getLinkage(), DefaultVisibility, true); return T.getLinkageAndVisibility(); @@ -229,9 +198,8 @@ getLVForType(const Type &T, LVComputatio /// \brief Get the most restrictive linkage for the types in the given /// template parameter list. For visibility purposes, template /// parameters are part of the signature of a template. -static LinkageInfo -getLVForTemplateParameterList(const TemplateParameterList *Params, - LVComputationKind computation) { +LinkageInfo LinkageComputer::getLVForTemplateParameterList( + const TemplateParameterList *Params, LVComputationKind computation) { LinkageInfo LV; for (const NamedDecl *P : *Params) { // Template type parameters are the most common and never @@ -283,10 +251,6 @@ getLVForTemplateParameterList(const Temp return LV; } -/// getLVForDecl - Get the linkage and visibility for the given declaration. -static LinkageInfo getLVForDecl(const NamedDecl *D, - LVComputationKind computation); - static const Decl *getOutermostFuncOrBlockContext(const Decl *D) { const Decl *Ret = nullptr; const DeclContext *DC = D->getDeclContext(); @@ -303,8 +267,9 @@ static const Decl *getOutermostFuncOrBlo /// /// Note that we don't take an LVComputationKind because we always /// want to honor the visibility of template arguments in the same way. -static LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args, - LVComputationKind computation) { +LinkageInfo +LinkageComputer::getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args, + LVComputationKind computation) { LinkageInfo LV; for (const TemplateArgument &Arg : Args) { @@ -346,9 +311,9 @@ static LinkageInfo getLVForTemplateArgum return LV; } -static LinkageInfo -getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, - LVComputationKind computation) { +LinkageInfo +LinkageComputer::getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, + LVComputationKind computation) { return getLVForTemplateArgumentList(TArgs.asArray(), computation); } @@ -371,10 +336,10 @@ static bool shouldConsiderTemplateVisibi /// LVForValue. /// /// \param[out] LV the computation to use for the parent -static void -mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn, - const FunctionTemplateSpecializationInfo *specInfo, - LVComputationKind computation) { +void LinkageComputer::mergeTemplateLV( + LinkageInfo &LV, const FunctionDecl *fn, + const FunctionTemplateSpecializationInfo *specInfo, + LVComputationKind computation) { bool considerVisibility = shouldConsiderTemplateVisibility(fn, specInfo); @@ -449,9 +414,9 @@ static bool shouldConsiderTemplateVisibi /// Merge in template-related linkage and visibility for the given /// class template specialization. -static void mergeTemplateLV(LinkageInfo &LV, - const ClassTemplateSpecializationDecl *spec, - LVComputationKind computation) { +void LinkageComputer::mergeTemplateLV( + LinkageInfo &LV, const ClassTemplateSpecializationDecl *spec, + LVComputationKind computation) { bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation); // Merge information from the template parameters, but ignore @@ -501,9 +466,9 @@ static bool shouldConsiderTemplateVisibi /// Merge in template-related linkage and visibility for the given /// variable template specialization. As usual, follow class template /// specialization logic up to initialization. -static void mergeTemplateLV(LinkageInfo &LV, - const VarTemplateSpecializationDecl *spec, - LVComputationKind computation) { +void LinkageComputer::mergeTemplateLV(LinkageInfo &LV, + const VarTemplateSpecializationDecl *spec, + LVComputationKind computation) { bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation); // Merge information from the template parameters, but ignore @@ -603,8 +568,9 @@ static LinkageInfo getExternalLinkageFor return LinkageInfo::external(); } -static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, - LVComputationKind computation) { +LinkageInfo +LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, + LVComputationKind computation) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && "Not a name having namespace scope"); ASTContext &Context = D->getASTContext(); @@ -883,8 +849,9 @@ static LinkageInfo getLVForNamespaceScop return LV; } -static LinkageInfo getLVForClassMember(const NamedDecl *D, - LVComputationKind computation) { +LinkageInfo +LinkageComputer::getLVForClassMember(const NamedDecl *D, + LVComputationKind computation) { // 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 @@ -1041,15 +1008,13 @@ static LinkageInfo getLVForClassMember(c void NamedDecl::anchor() { } -static LinkageInfo computeLVForDecl(const NamedDecl *D, - LVComputationKind computation); - bool NamedDecl::isLinkageValid() const { if (!hasCachedLinkage()) return true; - return computeLVForDecl(this, LVForLinkageOnly).getLinkage() == - getCachedLinkage(); + Linkage L = + LinkageComputer{}.computeLVForDecl(this, LVForLinkageOnly).getLinkage(); + return L == getCachedLinkage(); } ObjCStringFormatFamily NamedDecl::getObjCFStringFormattingFamily() const { @@ -1068,13 +1033,11 @@ ObjCStringFormatFamily NamedDecl::getObj Linkage NamedDecl::getLinkageInternal() const { // We don't care about visibility here, so ask for the cheapest // possible visibility analysis. - return getLVForDecl(this, LVForLinkageOnly).getLinkage(); + return LinkageComputer{}.getLVForDecl(this, LVForLinkageOnly).getLinkage(); } LinkageInfo NamedDecl::getLinkageAndVisibility() const { - LVComputationKind computation = - (usesTypeVisibility(this) ? LVForType : LVForValue); - return getLVForDecl(this, computation); + return LinkageComputer{}.getDeclLinkageAndVisibility(this); } static Optional<Visibility> @@ -1152,8 +1115,9 @@ NamedDecl::getExplicitVisibility(Explici return getExplicitVisibilityAux(this, kind, false); } -static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, - LVComputationKind computation) { +LinkageInfo LinkageComputer::getLVForClosure(const DeclContext *DC, + Decl *ContextDecl, + LVComputationKind computation) { // This lambda has its linkage/visibility determined by its owner. if (ContextDecl) { if (isa<ParmVarDecl>(ContextDecl)) @@ -1170,8 +1134,8 @@ static LinkageInfo getLVForClosure(const return LinkageInfo::external(); } -static LinkageInfo getLVForLocalDecl(const NamedDecl *D, - LVComputationKind computation) { +LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D, + LVComputationKind computation) { if (const auto *Function = dyn_cast<FunctionDecl>(D)) { if (Function->isInAnonymousNamespace() && !Function->isInExternCContext()) @@ -1264,8 +1228,8 @@ getOutermostEnclosingLambda(const CXXRec return Ret; } -static LinkageInfo computeLVForDecl(const NamedDecl *D, - LVComputationKind computation) { +LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D, + LVComputationKind computation) { // Internal_linkage attribute overrides other considerations. if (D->hasAttr<InternalLinkageAttr>()) return getInternalLinkageFor(D); @@ -1384,56 +1348,51 @@ static LinkageInfo computeLVForDecl(cons return LinkageInfo::none(); } -namespace clang { -class LinkageComputer { -public: - static LinkageInfo getLVForDecl(const NamedDecl *D, - LVComputationKind computation) { - // Internal_linkage attribute overrides other considerations. - if (D->hasAttr<InternalLinkageAttr>()) - return getInternalLinkageFor(D); - - if (computation == LVForLinkageOnly && D->hasCachedLinkage()) - return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false); - - LinkageInfo LV = computeLVForDecl(D, computation); - if (D->hasCachedLinkage()) - assert(D->getCachedLinkage() == LV.getLinkage()); +/// getLVForDecl - Get the linkage and visibility for the given declaration. +LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D, + LVComputationKind computation) { + // Internal_linkage attribute overrides other considerations. + if (D->hasAttr<InternalLinkageAttr>()) + return getInternalLinkageFor(D); + + if (computation == LVForLinkageOnly && D->hasCachedLinkage()) + return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false); - D->setCachedLinkage(LV.getLinkage()); + LinkageInfo LV = computeLVForDecl(D, computation); + if (D->hasCachedLinkage()) + assert(D->getCachedLinkage() == LV.getLinkage()); + + D->setCachedLinkage(LV.getLinkage()); #ifndef NDEBUG - // In C (because of gnu inline) and in c++ with microsoft extensions an - // static can follow an extern, so we can have two decls with different - // linkages. - const LangOptions &Opts = D->getASTContext().getLangOpts(); - if (!Opts.CPlusPlus || Opts.MicrosoftExt) - return LV; + // In C (because of gnu inline) and in c++ with microsoft extensions an + // static can follow an extern, so we can have two decls with different + // linkages. + const LangOptions &Opts = D->getASTContext().getLangOpts(); + if (!Opts.CPlusPlus || Opts.MicrosoftExt) + return LV; - // We have just computed the linkage for this decl. By induction we know - // that all other computed linkages match, check that the one we just - // computed also does. - NamedDecl *Old = nullptr; - for (auto I : D->redecls()) { - auto *T = cast<NamedDecl>(I); - if (T == D) - continue; - if (!T->isInvalidDecl() && T->hasCachedLinkage()) { - Old = T; - break; - } + // We have just computed the linkage for this decl. By induction we know + // that all other computed linkages match, check that the one we just + // computed also does. + NamedDecl *Old = nullptr; + for (auto I : D->redecls()) { + auto *T = cast<NamedDecl>(I); + if (T == D) + continue; + if (!T->isInvalidDecl() && T->hasCachedLinkage()) { + Old = T; + break; } - assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage()); + } + assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage()); #endif - return LV; - } -}; + return LV; } -static LinkageInfo getLVForDecl(const NamedDecl *D, - LVComputationKind computation) { - return clang::LinkageComputer::getLVForDecl(D, computation); +LinkageInfo LinkageComputer::getDeclLinkageAndVisibility(const NamedDecl *D) { + return getLVForDecl(D, usesTypeVisibility(D) ? LVForType : LVForValue); } void NamedDecl::printName(raw_ostream &os) const { Added: cfe/trunk/lib/AST/Linkage.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Linkage.h?rev=310436&view=auto ============================================================================== --- cfe/trunk/lib/AST/Linkage.h (added) +++ cfe/trunk/lib/AST/Linkage.h Tue Aug 8 21:02:49 2017 @@ -0,0 +1,114 @@ +//===----- Linkage.h - Linkage calculation-related utilities ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides AST-internal utilities for linkage and visibility +// calculation. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_AST_LINKAGE_H +#define LLVM_CLANG_LIB_AST_LINKAGE_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { +enum : unsigned { + IgnoreExplicitVisibilityBit = 2, + IgnoreAllVisibilityBit = 4 +}; + +/// Kinds of LV computation. The linkage side of the computation is +/// always the same, but different things can change how visibility is +/// computed. +enum LVComputationKind { + /// Do an LV computation for, ultimately, a type. + /// Visibility may be restricted by type visibility settings and + /// the visibility of template arguments. + LVForType = NamedDecl::VisibilityForType, + + /// Do an LV computation for, ultimately, a non-type declaration. + /// Visibility may be restricted by value visibility settings and + /// the visibility of template arguments. + LVForValue = NamedDecl::VisibilityForValue, + + /// Do an LV computation for, ultimately, a type that already has + /// some sort of explicit visibility. Visibility may only be + /// restricted by the visibility of template arguments. + LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit), + + /// Do an LV computation for, ultimately, a non-type declaration + /// that already has some sort of explicit visibility. Visibility + /// may only be restricted by the visibility of template arguments. + LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit), + + /// Do an LV computation when we only care about the linkage. + LVForLinkageOnly = + LVForValue | IgnoreExplicitVisibilityBit | IgnoreAllVisibilityBit +}; + +class LinkageComputer { + LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args, + LVComputationKind computation); + + LinkageInfo getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, + LVComputationKind computation); + + void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn, + const FunctionTemplateSpecializationInfo *specInfo, + LVComputationKind computation); + + void mergeTemplateLV(LinkageInfo &LV, + const ClassTemplateSpecializationDecl *spec, + LVComputationKind computation); + + void mergeTemplateLV(LinkageInfo &LV, + const VarTemplateSpecializationDecl *spec, + LVComputationKind computation); + + LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, + LVComputationKind computation); + + LinkageInfo getLVForClassMember(const NamedDecl *D, + LVComputationKind computation); + + LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, + LVComputationKind computation); + + LinkageInfo getLVForLocalDecl(const NamedDecl *D, + LVComputationKind computation); + + LinkageInfo getLVForType(const Type &T, LVComputationKind computation); + + LinkageInfo getLVForTemplateParameterList(const TemplateParameterList *Params, + LVComputationKind computation); + +public: + LinkageInfo computeLVForDecl(const NamedDecl *D, + LVComputationKind computation); + + LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation); + + LinkageInfo computeTypeLinkageInfo(const Type *T); + LinkageInfo computeTypeLinkageInfo(QualType T) { + return computeTypeLinkageInfo(T.getTypePtr()); + } + + LinkageInfo getDeclLinkageAndVisibility(const NamedDecl *D); + + LinkageInfo getTypeLinkageAndVisibility(const Type *T); + LinkageInfo getTypeLinkageAndVisibility(QualType T) { + return getTypeLinkageAndVisibility(T.getTypePtr()); + } +}; +} // namespace clang + +#endif Modified: cfe/trunk/lib/AST/Type.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=310436&r1=310435&r2=310436&view=diff ============================================================================== --- cfe/trunk/lib/AST/Type.cpp (original) +++ cfe/trunk/lib/AST/Type.cpp Tue Aug 8 21:02:49 2017 @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/Type.h" +#include "Linkage.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" @@ -3428,9 +3429,7 @@ bool Type::hasUnnamedOrLocalType() const return TypeBits.hasLocalOrUnnamedType(); } -static LinkageInfo computeLinkageInfo(QualType T); - -static LinkageInfo computeLinkageInfo(const Type *T) { +LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { switch (T->getTypeClass()) { #define TYPE(Class,Base) #define NON_CANONICAL_TYPE(Class,Base) case Type::Class: @@ -3457,72 +3456,75 @@ static LinkageInfo computeLinkageInfo(co return cast<TagType>(T)->getDecl()->getLinkageAndVisibility(); case Type::Complex: - return computeLinkageInfo(cast<ComplexType>(T)->getElementType()); + return computeTypeLinkageInfo(cast<ComplexType>(T)->getElementType()); case Type::Pointer: - return computeLinkageInfo(cast<PointerType>(T)->getPointeeType()); + return computeTypeLinkageInfo(cast<PointerType>(T)->getPointeeType()); case Type::BlockPointer: - return computeLinkageInfo(cast<BlockPointerType>(T)->getPointeeType()); + return computeTypeLinkageInfo(cast<BlockPointerType>(T)->getPointeeType()); case Type::LValueReference: case Type::RValueReference: - return computeLinkageInfo(cast<ReferenceType>(T)->getPointeeType()); + return computeTypeLinkageInfo(cast<ReferenceType>(T)->getPointeeType()); case Type::MemberPointer: { const MemberPointerType *MPT = cast<MemberPointerType>(T); - LinkageInfo LV = computeLinkageInfo(MPT->getClass()); - LV.merge(computeLinkageInfo(MPT->getPointeeType())); + LinkageInfo LV = computeTypeLinkageInfo(MPT->getClass()); + LV.merge(computeTypeLinkageInfo(MPT->getPointeeType())); return LV; } case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: - return computeLinkageInfo(cast<ArrayType>(T)->getElementType()); + return computeTypeLinkageInfo(cast<ArrayType>(T)->getElementType()); case Type::Vector: case Type::ExtVector: - return computeLinkageInfo(cast<VectorType>(T)->getElementType()); + return computeTypeLinkageInfo(cast<VectorType>(T)->getElementType()); case Type::FunctionNoProto: - return computeLinkageInfo(cast<FunctionType>(T)->getReturnType()); + return computeTypeLinkageInfo(cast<FunctionType>(T)->getReturnType()); case Type::FunctionProto: { const FunctionProtoType *FPT = cast<FunctionProtoType>(T); - LinkageInfo LV = computeLinkageInfo(FPT->getReturnType()); + LinkageInfo LV = computeTypeLinkageInfo(FPT->getReturnType()); for (const auto &ai : FPT->param_types()) - LV.merge(computeLinkageInfo(ai)); + LV.merge(computeTypeLinkageInfo(ai)); return LV; } case Type::ObjCInterface: return cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility(); case Type::ObjCObject: - return computeLinkageInfo(cast<ObjCObjectType>(T)->getBaseType()); + return computeTypeLinkageInfo(cast<ObjCObjectType>(T)->getBaseType()); case Type::ObjCObjectPointer: - return computeLinkageInfo(cast<ObjCObjectPointerType>(T)->getPointeeType()); + return computeTypeLinkageInfo( + cast<ObjCObjectPointerType>(T)->getPointeeType()); case Type::Atomic: - return computeLinkageInfo(cast<AtomicType>(T)->getValueType()); + return computeTypeLinkageInfo(cast<AtomicType>(T)->getValueType()); case Type::Pipe: - return computeLinkageInfo(cast<PipeType>(T)->getElementType()); + return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType()); } llvm_unreachable("unhandled type class"); } -static LinkageInfo computeLinkageInfo(QualType T) { - return computeLinkageInfo(T.getTypePtr()); -} - bool Type::isLinkageValid() const { if (!TypeBits.isCacheValid()) return true; - return computeLinkageInfo(getCanonicalTypeInternal()).getLinkage() == - TypeBits.getLinkage(); + Linkage L = LinkageComputer{} + .computeTypeLinkageInfo(getCanonicalTypeInternal()) + .getLinkage(); + return L == TypeBits.getLinkage(); } -LinkageInfo Type::getLinkageAndVisibility() const { - if (!isCanonicalUnqualified()) - return computeLinkageInfo(getCanonicalTypeInternal()); +LinkageInfo LinkageComputer::getTypeLinkageAndVisibility(const Type *T) { + if (!T->isCanonicalUnqualified()) + return computeTypeLinkageInfo(T->getCanonicalTypeInternal()); - LinkageInfo LV = computeLinkageInfo(this); - assert(LV.getLinkage() == getLinkage()); + LinkageInfo LV = computeTypeLinkageInfo(T); + assert(LV.getLinkage() == T->getLinkage()); return LV; } +LinkageInfo Type::getLinkageAndVisibility() const { + return LinkageComputer{}.getTypeLinkageAndVisibility(this); +} + Optional<NullabilityKind> Type::getNullability(const ASTContext &context) const { QualType type(this, 0); do { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits