<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 21 June 2017 at 14:51, Bruno Cardoso Lopes <span dir="ltr"><<a href="mailto:bruno.cardoso@gmail.com" target="_blank">bruno.cardoso@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Richard,<br>
<br>
Somehow this commit caused some methods in ObjC to do not become<br>
visible in an interface when compiling with modules on. I filed<br>
<a href="https://bugs.llvm.org/show_bug.cgi?id=33552" rel="noreferrer" target="_blank">https://bugs.llvm.org/show_<wbr>bug.cgi?id=33552</a>, any idea what could have<br>
gone wrong here? `hasVisibleDeclarationImpl` doesn't seem to have<br>
changed the logic.<br></blockquote><div><br></div><div>DeclObjC.cpp is making some incorrect assumptions about what the isHidden() flag on Decls means. Looks like we're going to need to move all of the ObjC lookup machinery out of DeclObjC into Sema to allow it to perform correct visibility checks. (For what it's worth, this would already have been broken for Objective-C++ and local submodule visibility mode prior to this change, as those modes both have situations where the "Hidden" flag is not the complete story with regard to whether a declaration is visible in a particular lookup context.)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Thanks,<br>
<div class="HOEnZb"><div class="h5"><br>
On Wed, May 17, 2017 at 7:29 PM, Richard Smith via cfe-commits<br>
<<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br>
> Author: rsmith<br>
> Date: Wed May 17 21:29:20 2017<br>
> New Revision: 303322<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=303322&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=303322&view=rev</a><br>
> Log:<br>
> [modules] Switch from inferring owning modules based on source location to<br>
> inferring based on the current module at the point of creation.<br>
><br>
> This should result in no functional change except when building a preprocessed<br>
> module (or more generally when using #pragma clang module begin/end to switch<br>
> module in the middle of a file), in which case it allows us to correctly track<br>
> the owning module for declarations. We can't map from FileID to module in the<br>
> preprocessed module case, since all modules would have the same FileID.<br>
><br>
> There are still a couple of remaining places that try to infer a module from a<br>
> source location; I'll clean those up in follow-up changes.<br>
><br>
> Modified:<br>
>     cfe/trunk/include/clang/AST/<wbr>ASTContext.h<br>
>     cfe/trunk/include/clang/AST/<wbr>DeclBase.h<br>
>     cfe/trunk/include/clang/Basic/<wbr>LangOptions.h<br>
>     cfe/trunk/include/clang/Sema/<wbr>Sema.h<br>
>     cfe/trunk/include/clang/<wbr>Serialization/ASTWriter.h<br>
>     cfe/trunk/lib/CodeGen/<wbr>CGDebugInfo.cpp<br>
>     cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp<br>
>     cfe/trunk/lib/Sema/SemaLookup.<wbr>cpp<br>
>     cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp<br>
>     cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp<br>
>     cfe/trunk/lib/Serialization/<wbr>ASTWriterDecl.cpp<br>
>     cfe/trunk/test/Modules/<wbr>preprocess-module.cpp<br>
>     cfe/trunk/test/SemaCXX/<wbr>modules-ts.cppm<br>
><br>
> Modified: cfe/trunk/include/clang/AST/<wbr>ASTContext.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/AST/ASTContext.h?rev=<wbr>303322&r1=303321&r2=303322&<wbr>view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/include/clang/AST/<wbr>ASTContext.h (original)<br>
> +++ cfe/trunk/include/clang/AST/<wbr>ASTContext.h Wed May 17 21:29:20 2017<br>
> @@ -935,7 +935,7 @@ public:<br>
><br>
>    /// \brief Get the additional modules in which the definition \p Def has<br>
>    /// been merged.<br>
> -  ArrayRef<Module*> getModulesWithMergedDefinition<wbr>(NamedDecl *Def) {<br>
> +  ArrayRef<Module*> getModulesWithMergedDefinition<wbr>(const NamedDecl *Def) {<br>
>      auto MergedIt = MergedDefModules.find(Def);<br>
>      if (MergedIt == MergedDefModules.end())<br>
>        return None;<br>
><br>
> Modified: cfe/trunk/include/clang/AST/<wbr>DeclBase.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/AST/DeclBase.h?rev=<wbr>303322&r1=303321&r2=303322&<wbr>view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/include/clang/AST/<wbr>DeclBase.h (original)<br>
> +++ cfe/trunk/include/clang/AST/<wbr>DeclBase.h Wed May 17 21:29:20 2017<br>
> @@ -332,15 +332,15 @@ private:<br>
>    bool AccessDeclContextSanity() const;<br>
><br>
>  protected:<br>
> -<br>
>    Decl(Kind DK, DeclContext *DC, SourceLocation L)<br>
> -    : NextInContextAndBits(), DeclCtx(DC),<br>
> -      Loc(L), DeclKind(DK), InvalidDecl(0),<br>
> -      HasAttrs(false), Implicit(false), Used(false), Referenced(false),<br>
> -      Access(AS_none), FromASTFile(0), Hidden(DC && cast<Decl>(DC)->Hidden),<br>
> -      IdentifierNamespace(<wbr>getIdentifierNamespaceForKind(<wbr>DK)),<br>
> -      CacheValidAndLinkage(0)<br>
> -  {<br>
> +      : NextInContextAndBits(), DeclCtx(DC), Loc(L), DeclKind(DK),<br>
> +        InvalidDecl(0), HasAttrs(false), Implicit(false), Used(false),<br>
> +        Referenced(false), Access(AS_none), FromASTFile(0),<br>
> +        Hidden(DC && cast<Decl>(DC)->Hidden &&<br>
> +               (!cast<Decl>(DC)-><wbr>isFromASTFile() ||<br>
> +                hasLocalOwningModuleStorage())<wbr>),<br>
> +        IdentifierNamespace(<wbr>getIdentifierNamespaceForKind(<wbr>DK)),<br>
> +        CacheValidAndLinkage(0) {<br>
>      if (StatisticsEnabled) add(DK);<br>
>    }<br>
><br>
> @@ -698,6 +698,9 @@ public:<br>
>    Module *getLocalOwningModule() const {<br>
>      if (isFromASTFile() || !Hidden)<br>
>        return nullptr;<br>
> +<br>
> +    assert(<wbr>hasLocalOwningModuleStorage() &&<br>
> +           "hidden local decl but no local module storage");<br>
>      return reinterpret_cast<Module *const *>(this)[-1];<br>
>    }<br>
>    void setLocalOwningModule(Module *M) {<br>
><br>
> Modified: cfe/trunk/include/clang/Basic/<wbr>LangOptions.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/LangOptions.h?rev=<wbr>303322&r1=303321&r2=303322&<wbr>view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/include/clang/Basic/<wbr>LangOptions.h (original)<br>
> +++ cfe/trunk/include/clang/Basic/<wbr>LangOptions.h Wed May 17 21:29:20 2017<br>
> @@ -168,7 +168,7 @@ public:<br>
><br>
>    /// Do we need to track the owning module for a local declaration?<br>
>    bool trackLocalOwningModule() const {<br>
> -    return ModulesLocalVisibility;<br>
> +    return isCompilingModule() || ModulesLocalVisibility || ModulesTS;<br>
>    }<br>
><br>
>    bool isSignedOverflowDefined() const {<br>
><br>
> Modified: cfe/trunk/include/clang/Sema/<wbr>Sema.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Sema/Sema.h?rev=303322&<wbr>r1=303321&r2=303322&view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/include/clang/Sema/<wbr>Sema.h (original)<br>
> +++ cfe/trunk/include/clang/Sema/<wbr>Sema.h Wed May 17 21:29:20 2017<br>
> @@ -1507,6 +1507,12 @@ public:<br>
>    hasVisibleDefaultArgument(<wbr>const NamedDecl *D,<br>
>                              llvm::SmallVectorImpl<Module *> *Modules = nullptr);<br>
><br>
> +  /// Determine if there is a visible declaration of \p D that is an explicit<br>
> +  /// specialization declaration for a specialization of a template. (For a<br>
> +  /// member specialization, use hasVisibleMemberSpecialization<wbr>.)<br>
> +  bool hasVisibleExplicitSpecializati<wbr>on(<br>
> +      const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr);<br>
> +<br>
>    /// Determine if there is a visible declaration of \p D that is a member<br>
>    /// specialization declaration (as opposed to an instantiated declaration).<br>
>    bool hasVisibleMemberSpecialization<wbr>(<br>
> @@ -2360,7 +2366,7 @@ public:<br>
>    void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld);<br>
>    void MergeVarDeclExceptionSpecs(<wbr>VarDecl *New, VarDecl *Old);<br>
>    bool checkVarDeclRedefinition(<wbr>VarDecl *OldDefn, VarDecl *NewDefn);<br>
> -  void notePreviousDefinition(<wbr>SourceLocation Old, SourceLocation New);<br>
> +  void notePreviousDefinition(const NamedDecl *Old, SourceLocation New);<br>
>    bool MergeCXXFunctionDecl(<wbr>FunctionDecl *New, FunctionDecl *Old, Scope *S);<br>
><br>
>    // AssignmentAction - This is used by all the assignment diagnostic functions<br>
><br>
> Modified: cfe/trunk/include/clang/<wbr>Serialization/ASTWriter.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Serialization/ASTWriter.<wbr>h?rev=303322&r1=303321&r2=<wbr>303322&view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/include/clang/<wbr>Serialization/ASTWriter.h (original)<br>
> +++ cfe/trunk/include/clang/<wbr>Serialization/ASTWriter.h Wed May 17 21:29:20 2017<br>
> @@ -627,10 +627,6 @@ public:<br>
>    /// \brief Add a version tuple to the given record<br>
>    void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record);<br>
><br>
> -  /// \brief Infer the submodule ID that contains an entity at the given<br>
> -  /// source location.<br>
> -  serialization::SubmoduleID inferSubmoduleIDFromLocation(<wbr>SourceLocation Loc);<br>
> -<br>
>    /// \brief Retrieve or create a submodule ID for this module, or return 0 if<br>
>    /// the submodule is neither local (a submodle of the currently-written module)<br>
>    /// nor from an imported module.<br>
><br>
> Modified: cfe/trunk/lib/CodeGen/<wbr>CGDebugInfo.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>CGDebugInfo.cpp?rev=303322&r1=<wbr>303321&r2=303322&view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/lib/CodeGen/<wbr>CGDebugInfo.cpp (original)<br>
> +++ cfe/trunk/lib/CodeGen/<wbr>CGDebugInfo.cpp Wed May 17 21:29:20 2017<br>
> @@ -2613,7 +2613,7 @@ llvm::DIModule *CGDebugInfo::getParentMo<br>
>      // best to make this behavior a command line or debugger tuning<br>
>      // option.<br>
>      FullSourceLoc Loc(D->getLocation(), CGM.getContext().<wbr>getSourceManager());<br>
> -    if (Module *M = ClangModuleMap-><wbr>inferModuleFromLocation(Loc)) {<br>
> +    if (Module *M = D->getOwningModule()) {<br>
>        // This is a (sub-)module.<br>
>        auto Info = ExternalASTSource::<wbr>ASTSourceDescriptor(*M);<br>
>        return getOrCreateModuleRef(Info, /*SkeletonCU=*/false);<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaDecl.cpp?rev=303322&r1=<wbr>303321&r2=303322&view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp Wed May 17 21:29:20 2017<br>
> @@ -2021,7 +2021,7 @@ bool Sema::isIncompatibleTypedef(<wbr>TypeDec<br>
>      Diag(New->getLocation(), diag::err_redefinition_<wbr>variably_modified_typedef)<br>
>        << Kind << NewType;<br>
>      if (Old->getLocation().isValid())<br>
> -      notePreviousDefinition(Old-><wbr>getLocation(), New->getLocation());<br>
> +      notePreviousDefinition(Old, New->getLocation());<br>
>      New->setInvalidDecl();<br>
>      return true;<br>
>    }<br>
> @@ -2034,7 +2034,7 @@ bool Sema::isIncompatibleTypedef(<wbr>TypeDec<br>
>      Diag(New->getLocation(), diag::err_redefinition_<wbr>different_typedef)<br>
>        << Kind << NewType << OldType;<br>
>      if (Old->getLocation().isValid())<br>
> -      notePreviousDefinition(Old-><wbr>getLocation(), New->getLocation());<br>
> +      notePreviousDefinition(Old, New->getLocation());<br>
>      New->setInvalidDecl();<br>
>      return true;<br>
>    }<br>
> @@ -2101,7 +2101,7 @@ void Sema::MergeTypedefNameDecl(<wbr>Scope *S<br>
><br>
>      NamedDecl *OldD = OldDecls.<wbr>getRepresentativeDecl();<br>
>      if (OldD->getLocation().isValid()<wbr>)<br>
> -      notePreviousDefinition(OldD-><wbr>getLocation(), New->getLocation());<br>
> +      notePreviousDefinition(OldD, New->getLocation());<br>
><br>
>      return New->setInvalidDecl();<br>
>    }<br>
> @@ -2193,7 +2193,7 @@ void Sema::MergeTypedefNameDecl(<wbr>Scope *S<br>
><br>
>      Diag(New->getLocation(), diag::err_redefinition)<br>
>        << New->getDeclName();<br>
> -    notePreviousDefinition(Old-><wbr>getLocation(), New->getLocation());<br>
> +    notePreviousDefinition(Old, New->getLocation());<br>
>      return New->setInvalidDecl();<br>
>    }<br>
><br>
> @@ -2214,7 +2214,7 @@ void Sema::MergeTypedefNameDecl(<wbr>Scope *S<br>
><br>
>    Diag(New->getLocation(), diag::ext_redefinition_of_<wbr>typedef)<br>
>      << New->getDeclName();<br>
> -  notePreviousDefinition(Old-><wbr>getLocation(), New->getLocation());<br>
> +  notePreviousDefinition(Old, New->getLocation());<br>
>  }<br>
><br>
>  /// DeclhasAttr - returns true if decl Declaration already has the target<br>
> @@ -2448,7 +2448,7 @@ static bool mergeDeclAttribute(Sema &S,<br>
>    return false;<br>
>  }<br>
><br>
> -static const Decl *getDefinition(const Decl *D) {<br>
> +static const NamedDecl *getDefinition(const Decl *D) {<br>
>    if (const TagDecl *TD = dyn_cast<TagDecl>(D))<br>
>      return TD->getDefinition();<br>
>    if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {<br>
> @@ -2475,7 +2475,7 @@ static void checkNewAttributesAfterDef(S<br>
>    if (!New->hasAttrs())<br>
>      return;<br>
><br>
> -  const Decl *Def = getDefinition(Old);<br>
> +  const NamedDecl *Def = getDefinition(Old);<br>
>    if (!Def || Def == New)<br>
>      return;<br>
><br>
> @@ -2502,7 +2502,7 @@ static void checkNewAttributesAfterDef(S<br>
>                              : diag::err_redefinition;<br>
>          S.Diag(VD->getLocation(), Diag) << VD->getDeclName();<br>
>          if (Diag == diag::err_redefinition)<br>
> -          S.notePreviousDefinition(Def-><wbr>getLocation(), VD->getLocation());<br>
> +          S.notePreviousDefinition(Def, VD->getLocation());<br>
>          else<br>
>            S.Diag(Def->getLocation(), diag::note_previous_<wbr>definition);<br>
>          VD->setInvalidDecl();<br>
> @@ -2891,7 +2891,7 @@ bool Sema::MergeFunctionDecl(<wbr>FunctionDec<br>
>      } else {<br>
>        Diag(New->getLocation(), diag::err_redefinition_<wbr>different_kind)<br>
>          << New->getDeclName();<br>
> -      notePreviousDefinition(OldD-><wbr>getLocation(), New->getLocation());<br>
> +      notePreviousDefinition(OldD, New->getLocation());<br>
>        return true;<br>
>      }<br>
>    }<br>
> @@ -2928,7 +2928,7 @@ bool Sema::MergeFunctionDecl(<wbr>FunctionDec<br>
>        !Old->hasAttr<<wbr>InternalLinkageAttr>()) {<br>
>      Diag(New->getLocation(), diag::err_internal_linkage_<wbr>redeclaration)<br>
>          << New->getDeclName();<br>
> -    notePreviousDefinition(Old-><wbr>getLocation(), New->getLocation());<br>
> +    notePreviousDefinition(Old, New->getLocation());<br>
>      New->dropAttr<<wbr>InternalLinkageAttr>();<br>
>    }<br>
><br>
> @@ -3657,7 +3657,7 @@ void Sema::MergeVarDecl(VarDecl *New, Lo<br>
>    if (!Old) {<br>
>      Diag(New->getLocation(), diag::err_redefinition_<wbr>different_kind)<br>
>          << New->getDeclName();<br>
> -    notePreviousDefinition(<wbr>Previous.<wbr>getRepresentativeDecl()-><wbr>getLocation(),<br>
> +    notePreviousDefinition(<wbr>Previous.<wbr>getRepresentativeDecl(),<br>
>                             New->getLocation());<br>
>      return New->setInvalidDecl();<br>
>    }<br>
> @@ -3687,7 +3687,7 @@ void Sema::MergeVarDecl(VarDecl *New, Lo<br>
>        Old->getStorageClass() == SC_None &&<br>
>        !Old->hasAttr<WeakImportAttr>(<wbr>)) {<br>
>      Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName();<br>
> -    notePreviousDefinition(Old-><wbr>getLocation(), New->getLocation());<br>
> +    notePreviousDefinition(Old, New->getLocation());<br>
>      // Remove weak_import attribute on new declaration.<br>
>      New->dropAttr<WeakImportAttr>(<wbr>);<br>
>    }<br>
> @@ -3696,7 +3696,7 @@ void Sema::MergeVarDecl(VarDecl *New, Lo<br>
>        !Old->hasAttr<<wbr>InternalLinkageAttr>()) {<br>
>      Diag(New->getLocation(), diag::err_internal_linkage_<wbr>redeclaration)<br>
>          << New->getDeclName();<br>
> -    notePreviousDefinition(Old-><wbr>getLocation(), New->getLocation());<br>
> +    notePreviousDefinition(Old, New->getLocation());<br>
>      New->dropAttr<<wbr>InternalLinkageAttr>();<br>
>    }<br>
><br>
> @@ -3853,29 +3853,22 @@ void Sema::MergeVarDecl(VarDecl *New, Lo<br>
>      New->setImplicitlyInline();<br>
>  }<br>
><br>
> -void Sema::notePreviousDefinition(<wbr>SourceLocation Old, SourceLocation New) {<br>
> +void Sema::notePreviousDefinition(<wbr>const NamedDecl *Old, SourceLocation New) {<br>
>    SourceManager &SrcMgr = getSourceManager();<br>
>    auto FNewDecLoc = SrcMgr.getDecomposedLoc(New);<br>
> -  auto FOldDecLoc = SrcMgr.getDecomposedLoc(Old);<br>
> +  auto FOldDecLoc = SrcMgr.getDecomposedLoc(Old-><wbr>getLocation());<br>
>    auto *FNew = SrcMgr.getFileEntryForID(<wbr>FNewDecLoc.first);<br>
>    auto *FOld = SrcMgr.getFileEntryForID(<wbr>FOldDecLoc.first);<br>
>    auto &HSI = PP.getHeaderSearchInfo();<br>
> -  StringRef HdrFilename = SrcMgr.getFilename(SrcMgr.<wbr>getSpellingLoc(Old));<br>
> +  StringRef HdrFilename =<br>
> +      SrcMgr.getFilename(SrcMgr.<wbr>getSpellingLoc(Old-><wbr>getLocation()));<br>
><br>
> -  auto noteFromModuleOrInclude = [&](SourceLocation &Loc,<br>
> -                                     SourceLocation &IncLoc) -> bool {<br>
> -    Module *Mod = nullptr;<br>
> +  auto noteFromModuleOrInclude = [&](Module *Mod,<br>
> +                                     SourceLocation IncLoc) -> bool {<br>
>      // Redefinition errors with modules are common with non modular mapped<br>
>      // headers, example: a non-modular header H in module A that also gets<br>
>      // included directly in a TU. Pointing twice to the same header/definition<br>
>      // is confusing, try to get better diagnostics when modules is on.<br>
> -    if (getLangOpts().Modules) {<br>
> -      auto ModLoc = SrcMgr.getModuleImportLoc(Old)<wbr>;<br>
> -      if (!ModLoc.first.isInvalid())<br>
> -        Mod = HSI.getModuleMap().<wbr>inferModuleFromLocation(<br>
> -            FullSourceLoc(Loc, SrcMgr));<br>
> -    }<br>
> -<br>
>      if (IncLoc.isValid()) {<br>
>        if (Mod) {<br>
>          Diag(IncLoc, diag::note_redefinition_<wbr>modules_same_file)<br>
> @@ -3899,19 +3892,19 @@ void Sema::notePreviousDefinition(<wbr>Source<br>
>    if (FNew == FOld && FNewDecLoc.second == FOldDecLoc.second) {<br>
>      SourceLocation OldIncLoc = SrcMgr.getIncludeLoc(<wbr>FOldDecLoc.first);<br>
>      SourceLocation NewIncLoc = SrcMgr.getIncludeLoc(<wbr>FNewDecLoc.first);<br>
> -    EmittedDiag = noteFromModuleOrInclude(Old, OldIncLoc);<br>
> -    EmittedDiag |= noteFromModuleOrInclude(New, NewIncLoc);<br>
> +    EmittedDiag = noteFromModuleOrInclude(Old-><wbr>getOwningModule(), OldIncLoc);<br>
> +    EmittedDiag |= noteFromModuleOrInclude(<wbr>getCurrentModule(), NewIncLoc);<br>
><br>
>      // If the header has no guards, emit a note suggesting one.<br>
>      if (FOld && !HSI.<wbr>isFileMultipleIncludeGuarded(<wbr>FOld))<br>
> -      Diag(Old, diag::note_use_ifdef_guards);<br>
> +      Diag(Old->getLocation(), diag::note_use_ifdef_guards);<br>
><br>
>      if (EmittedDiag)<br>
>        return;<br>
>    }<br>
><br>
>    // Redefinition coming from different files or couldn't do better above.<br>
> -  Diag(Old, diag::note_previous_<wbr>definition);<br>
> +  Diag(Old->getLocation(), diag::note_previous_<wbr>definition);<br>
>  }<br>
><br>
>  /// We've just determined that \p Old and \p New both appear to be definitions<br>
> @@ -3934,7 +3927,7 @@ bool Sema::<wbr>checkVarDeclRedefinition(VarD<br>
>      return false;<br>
>    } else {<br>
>      Diag(New->getLocation(), diag::err_redefinition) << New;<br>
> -    notePreviousDefinition(Old-><wbr>getLocation(), New->getLocation());<br>
> +    notePreviousDefinition(Old, New->getLocation());<br>
>      New->setInvalidDecl();<br>
>      return true;<br>
>    }<br>
> @@ -13503,9 +13496,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned<br>
>              } else if (TUK == TUK_Reference &&<br>
>                         (PrevTagDecl-><wbr>getFriendObjectKind() ==<br>
>                              Decl::FOK_Undeclared ||<br>
> -                        PP.<wbr>getModuleContainingLocation(<br>
> -                            PrevDecl->getLocation()) !=<br>
> -                            PP.<wbr>getModuleContainingLocation(<wbr>KWLoc)) &&<br>
> +                        PrevDecl->getOwningModule() != getCurrentModule()) &&<br>
>                         SS.isEmpty()) {<br>
>                // This declaration is a reference to an existing entity, but<br>
>                // has different visibility from that entity: it either makes<br>
> @@ -13561,7 +13552,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned<br>
>                    Diag(NameLoc, diag::warn_redefinition_in_<wbr>param_list) << Name;<br>
>                  else<br>
>                    Diag(NameLoc, diag::err_redefinition) << Name;<br>
> -                notePreviousDefinition(Def-><wbr>getLocation(),<br>
> +                notePreviousDefinition(Def,<br>
>                                         NameLoc.isValid() ? NameLoc : KWLoc);<br>
>                  // If this is a redefinition, recover by making this<br>
>                  // struct be anonymous, which will make any later<br>
> @@ -13652,7 +13643,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned<br>
>          // The tag name clashes with something else in the target scope,<br>
>          // issue an error and recover by making this tag be anonymous.<br>
>          Diag(NameLoc, diag::err_redefinition_<wbr>different_kind) << Name;<br>
> -        notePreviousDefinition(<wbr>PrevDecl->getLocation(), NameLoc);<br>
> +        notePreviousDefinition(<wbr>PrevDecl, NameLoc);<br>
>          Name = nullptr;<br>
>          Invalid = true;<br>
>        }<br>
> @@ -15356,7 +15347,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S,<br>
>          Diag(IdLoc, diag::err_redefinition_of_<wbr>enumerator) << Id;<br>
>        else<br>
>          Diag(IdLoc, diag::err_redefinition) << Id;<br>
> -      notePreviousDefinition(<wbr>PrevDecl->getLocation(), IdLoc);<br>
> +      notePreviousDefinition(<wbr>PrevDecl, IdLoc);<br>
>        return nullptr;<br>
>      }<br>
>    }<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaLookup.<wbr>cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaLookup.cpp?rev=303322&r1=<wbr>303321&r2=303322&view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/lib/Sema/SemaLookup.<wbr>cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaLookup.<wbr>cpp Wed May 17 21:29:20 2017<br>
> @@ -1420,11 +1420,46 @@ bool Sema::<wbr>hasVisibleDefaultArgument(con<br>
>                                       Modules);<br>
>  }<br>
><br>
> +template<typename Filter><br>
> +static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D,<br>
> +                                      llvm::SmallVectorImpl<Module *> *Modules,<br>
> +                                      Filter F) {<br>
> +  for (auto *Redecl : D->redecls()) {<br>
> +    auto *R = cast<NamedDecl>(Redecl);<br>
> +    if (!F(R))<br>
> +      continue;<br>
> +<br>
> +    if (S.isVisible(R))<br>
> +      return true;<br>
> +<br>
> +    if (Modules) {<br>
> +      Modules->push_back(R-><wbr>getOwningModule());<br>
> +      const auto &Merged = S.Context.<wbr>getModulesWithMergedDefinition<wbr>(R);<br>
> +      Modules->insert(Modules->end()<wbr>, Merged.begin(), Merged.end());<br>
> +    }<br>
> +  }<br>
> +<br>
> +  return false;<br>
> +}<br>
> +<br>
> +bool Sema::<wbr>hasVisibleExplicitSpecializati<wbr>on(<br>
> +    const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {<br>
> +  return hasVisibleDeclarationImpl(*<wbr>this, D, Modules, [](const NamedDecl *D) {<br>
> +    if (auto *RD = dyn_cast<CXXRecordDecl>(D))<br>
> +      return RD-><wbr>getTemplateSpecializationKind(<wbr>) == TSK_ExplicitSpecialization;<br>
> +    if (auto *FD = dyn_cast<FunctionDecl>(D))<br>
> +      return FD-><wbr>getTemplateSpecializationKind(<wbr>) == TSK_ExplicitSpecialization;<br>
> +    if (auto *VD = dyn_cast<VarDecl>(D))<br>
> +      return VD-><wbr>getTemplateSpecializationKind(<wbr>) == TSK_ExplicitSpecialization;<br>
> +    llvm_unreachable("unknown explicit specialization kind");<br>
> +  });<br>
> +}<br>
> +<br>
>  bool Sema::<wbr>hasVisibleMemberSpecialization<wbr>(<br>
>      const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {<br>
>    assert(isa<CXXRecordDecl>(D-><wbr>getDeclContext()) &&<br>
>           "not a member specialization");<br>
> -  for (auto *Redecl : D->redecls()) {<br>
> +  return hasVisibleDeclarationImpl(*<wbr>this, D, Modules, [](const NamedDecl *D) {<br>
>      // If the specialization is declared at namespace scope, then it's a member<br>
>      // specialization declaration. If it's lexically inside the class<br>
>      // definition then it was instantiated.<br>
> @@ -1432,19 +1467,8 @@ bool Sema::<wbr>hasVisibleMemberSpecializatio<br>
>      // FIXME: This is a hack. There should be a better way to determine this.<br>
>      // FIXME: What about MS-style explicit specializations declared within a<br>
>      //        class definition?<br>
> -    if (Redecl-><wbr>getLexicalDeclContext()-><wbr>isFileContext()) {<br>
> -      auto *NonConstR = const_cast<NamedDecl*>(cast<<wbr>NamedDecl>(Redecl));<br>
> -<br>
> -      if (isVisible(NonConstR))<br>
> -        return true;<br>
> -<br>
> -      if (Modules) {<br>
> -        Modules->push_back(<wbr>getOwningModule(NonConstR));<br>
> -        const auto &Merged = Context.<wbr>getModulesWithMergedDefinition<wbr>(NonConstR);<br>
> -        Modules->insert(Modules->end()<wbr>, Merged.begin(), Merged.end());<br>
> -      }<br>
> -    }<br>
> -  }<br>
> +    return D->getLexicalDeclContext()-><wbr>isFileContext();<br>
> +  });<br>
><br>
>    return false;<br>
>  }<br>
> @@ -1459,23 +1483,19 @@ bool Sema::<wbr>hasVisibleMemberSpecializatio<br>
>  /// your module can see, including those later on in your module).<br>
>  bool LookupResult::isVisibleSlow(<wbr>Sema &SemaRef, NamedDecl *D) {<br>
>    assert(D->isHidden() && "should not call this: not in slow case");<br>
> -  Module *DeclModule = nullptr;<br>
> -<br>
> -  if (SemaRef.getLangOpts().<wbr>ModulesLocalVisibility) {<br>
> -    DeclModule = SemaRef.getOwningModule(D);<br>
> -    if (!DeclModule) {<br>
> -      assert(!D->isHidden() && "hidden decl not from a module");<br>
> -      return true;<br>
> -    }<br>
><br>
> -    // If the owning module is visible, and the decl is not module private,<br>
> -    // then the decl is visible too. (Module private is ignored within the same<br>
> -    // top-level module.)<br>
> -    if ((!D->isFromASTFile() || !D->isModulePrivate()) &&<br>
> -        (SemaRef.isModuleVisible(<wbr>DeclModule) ||<br>
> -         SemaRef.<wbr>hasVisibleMergedDefinition(D))<wbr>)<br>
> -      return true;<br>
> -  }<br>
> +  Module *DeclModule = SemaRef.getOwningModule(D);<br>
> +  assert(DeclModule && "hidden decl not from a module");<br>
> +<br>
> +  // If the owning module is visible, and the decl is not module private,<br>
> +  // then the decl is visible too. (Module private is ignored within the same<br>
> +  // top-level module.)<br>
> +  // FIXME: Check the owning module for module-private declarations rather than<br>
> +  // assuming "same AST file" is the same thing as "same module".<br>
> +  if ((!D->isFromASTFile() || !D->isModulePrivate()) &&<br>
> +      (SemaRef.isModuleVisible(<wbr>DeclModule) ||<br>
> +       SemaRef.<wbr>hasVisibleMergedDefinition(D))<wbr>)<br>
> +    return true;<br>
><br>
>    // If this declaration is not at namespace scope nor module-private,<br>
>    // then it is visible if its lexical parent has a visible definition.<br>
> @@ -1571,20 +1591,8 @@ static NamedDecl *findAcceptableDecl(Sem<br>
>  bool Sema::<wbr>hasVisibleDeclarationSlow(<wbr>const NamedDecl *D,<br>
>                                       llvm::SmallVectorImpl<Module *> *Modules) {<br>
>    assert(!isVisible(D) && "not in slow case");<br>
> -<br>
> -  for (auto *Redecl : D->redecls()) {<br>
> -    auto *NonConstR = const_cast<NamedDecl*>(cast<<wbr>NamedDecl>(Redecl));<br>
> -    if (isVisible(NonConstR))<br>
> -      return true;<br>
> -<br>
> -    if (Modules) {<br>
> -      Modules->push_back(<wbr>getOwningModule(NonConstR));<br>
> -      const auto &Merged = Context.<wbr>getModulesWithMergedDefinition<wbr>(NonConstR);<br>
> -      Modules->insert(Modules->end()<wbr>, Merged.begin(), Merged.end());<br>
> -    }<br>
> -  }<br>
> -<br>
> -  return false;<br>
> +  return hasVisibleDeclarationImpl(*<wbr>this, D, Modules,<br>
> +                                   [](const NamedDecl *) { return true; });<br>
>  }<br>
><br>
>  NamedDecl *LookupResult::<wbr>getAcceptableDeclSlow(<wbr>NamedDecl *D) const {<br>
> @@ -4957,6 +4965,14 @@ void Sema::diagnoseMissingImport(<wbr>SourceL<br>
>                                   MissingImportKind MIK, bool Recover) {<br>
>    assert(!Modules.empty());<br>
><br>
> +  // Weed out duplicates from module list.<br>
> +  llvm::SmallVector<Module*, 8> UniqueModules;<br>
> +  llvm::SmallDenseSet<Module*, 8> UniqueModuleSet;<br>
> +  for (auto *M : Modules)<br>
> +    if (UniqueModuleSet.insert(M).<wbr>second)<br>
> +      UniqueModules.push_back(M);<br>
> +  Modules = UniqueModules;<br>
> +<br>
>    if (Modules.size() > 1) {<br>
>      std::string ModuleList;<br>
>      unsigned N = 0;<br>
><br>
> Modified: cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp?rev=303322&<wbr>r1=303321&r2=303322&view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp Wed May 17 21:29:20 2017<br>
> @@ -7901,6 +7901,7 @@ bool Sema::<wbr>CheckFunctionTemplateSpeciali<br>
>    TemplateSpecializationKind TSK = SpecInfo-><wbr>getTemplateSpecializationKind(<wbr>);<br>
>    if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation) {<br>
>      Specialization->setLocation(<wbr>FD->getLocation());<br>
> +    Specialization-><wbr>setLexicalDeclContext(FD-><wbr>getLexicalDeclContext());<br>
>      // C++11 [dcl.constexpr]p1: An explicit specialization of a constexpr<br>
>      // function can differ from the template declaration with respect to<br>
>      // the constexpr specifier.<br>
> @@ -7961,6 +7962,7 @@ bool Sema::<wbr>CheckFunctionTemplateSpeciali<br>
>        // FIXME: We need an update record for this AST mutation.<br>
>        Specialization-><wbr>setDeletedAsWritten(false);<br>
>      }<br>
> +    // FIXME: We need an update record for this AST mutation.<br>
>      SpecInfo-><wbr>setTemplateSpecializationKind(<wbr>TSK_ExplicitSpecialization);<br>
>      MarkUnusedFileScopedDecl(<wbr>Specialization);<br>
>    }<br>
> @@ -9745,7 +9747,7 @@ private:<br>
>        IsHiddenExplicitSpecialization =<br>
>            Spec-><wbr>getMemberSpecializationInfo()<br>
>                ? !S.<wbr>hasVisibleMemberSpecialization<wbr>(Spec, &Modules)<br>
> -              : !S.hasVisibleDeclaration(Spec)<wbr>;<br>
> +              : !S.<wbr>hasVisibleExplicitSpecializati<wbr>on(Spec, &Modules);<br>
>      } else {<br>
>        checkInstantiated(Spec);<br>
>      }<br>
><br>
> Modified: cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/<wbr>Serialization/ASTWriter.cpp?<wbr>rev=303322&r1=303321&r2=<wbr>303322&view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp (original)<br>
> +++ cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp Wed May 17 21:29:20 2017<br>
> @@ -2841,25 +2841,6 @@ void ASTWriter::WriteSubmodules(<wbr>Module *<br>
>           "non-imported submodule?");<br>
>  }<br>
><br>
> -serialization::SubmoduleID<br>
> -ASTWriter::<wbr>inferSubmoduleIDFromLocation(<wbr>SourceLocation Loc) {<br>
> -  if (Loc.isInvalid() || !WritingModule)<br>
> -    return 0; // No submodule<br>
> -<br>
> -  // Find the module that owns this location.<br>
> -  ModuleMap &ModMap = PP->getHeaderSearchInfo().<wbr>getModuleMap();<br>
> -  Module *OwningMod<br>
> -    = ModMap.<wbr>inferModuleFromLocation(<wbr>FullSourceLoc(Loc,PP-><wbr>getSourceManager()));<br>
> -  if (!OwningMod)<br>
> -    return 0;<br>
> -<br>
> -  // Check whether this submodule is part of our own module.<br>
> -  if (WritingModule != OwningMod && !OwningMod->isSubModuleOf(<wbr>WritingModule))<br>
> -    return 0;<br>
> -<br>
> -  return getSubmoduleID(OwningMod);<br>
> -}<br>
> -<br>
>  void ASTWriter::<wbr>WritePragmaDiagnosticMappings(<wbr>const DiagnosticsEngine &Diag,<br>
>                                                bool isModule) {<br>
>    llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64><br>
><br>
> Modified: cfe/trunk/lib/Serialization/<wbr>ASTWriterDecl.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/<wbr>Serialization/ASTWriterDecl.<wbr>cpp?rev=303322&r1=303321&r2=<wbr>303322&view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/lib/Serialization/<wbr>ASTWriterDecl.cpp (original)<br>
> +++ cfe/trunk/lib/Serialization/<wbr>ASTWriterDecl.cpp Wed May 17 21:29:20 2017<br>
> @@ -299,7 +299,7 @@ void ASTDeclWriter::VisitDecl(Decl *D) {<br>
>    Record.push_back(D-><wbr>isTopLevelDeclInObjCContainer(<wbr>));<br>
>    Record.push_back(D->getAccess(<wbr>));<br>
>    Record.push_back(D-><wbr>isModulePrivate());<br>
> -  Record.push_back(Writer.<wbr>inferSubmoduleIDFromLocation(<wbr>D->getLocation()));<br>
> +  Record.push_back(Writer.<wbr>getSubmoduleID(D-><wbr>getOwningModule()));<br>
><br>
>    // If this declaration injected a name into a context different from its<br>
>    // lexical context, and that context is an imported namespace, we need to<br>
><br>
> Modified: cfe/trunk/test/Modules/<wbr>preprocess-module.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/preprocess-module.cpp?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Modules/preprocess-module.cpp?<wbr>rev=303322&r1=303321&r2=<wbr>303322&view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/test/Modules/<wbr>preprocess-module.cpp (original)<br>
> +++ cfe/trunk/test/Modules/<wbr>preprocess-module.cpp Wed May 17 21:29:20 2017<br>
> @@ -25,8 +25,8 @@<br>
>  // RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -fmodule-map-file=%S/Inputs/<wbr>preprocess/module.modulemap -x c++-module-map-cpp-output %t/rewrite.ii -emit-module -o /dev/null<br>
><br>
>  // Check the module we built works.<br>
> -// RUN: %clang_cc1 -fmodules -fmodule-file=%t/no-rewrite.<wbr>pcm %s -verify<br>
> -// RUN: %clang_cc1 -fmodules -fmodule-file=%t/rewrite.pcm %s -verify<br>
> +// RUN: %clang_cc1 -fmodules -fmodule-file=%t/no-rewrite.<wbr>pcm %s -I%t -verify -fno-modules-error-recovery<br>
> +// RUN: %clang_cc1 -fmodules -fmodule-file=%t/rewrite.pcm %s -I%t -verify -fno-modules-error-recovery -DREWRITE<br>
><br>
><br>
>  // == module map<br>
> @@ -95,10 +95,12 @@<br>
>  // NO-REWRITE: #pragma clang module end<br>
><br>
><br>
> -// expected-no-diagnostics<br>
> -<br>
> -// FIXME: This should be rejected: we have not imported the submodule defining it yet.<br>
> -__FILE *a;<br>
> +__FILE *a; // expected-error {{declaration of '__FILE' must be imported}}<br>
> +#ifdef REWRITE<br>
> +// expected-note@rewrite.ii:1 {{here}}<br>
> +#else<br>
> +// expected-note@no-rewrite.ii:1 {{here}}<br>
> +#endif<br>
><br>
>  #pragma clang module import file<br>
><br>
><br>
> Modified: cfe/trunk/test/SemaCXX/<wbr>modules-ts.cppm<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/modules-ts.cppm?rev=303322&r1=303321&r2=303322&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>SemaCXX/modules-ts.cppm?rev=<wbr>303322&r1=303321&r2=303322&<wbr>view=diff</a><br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- cfe/trunk/test/SemaCXX/<wbr>modules-ts.cppm (original)<br>
> +++ cfe/trunk/test/SemaCXX/<wbr>modules-ts.cppm Wed May 17 21:29:20 2017<br>
> @@ -18,7 +18,8 @@ int n;<br>
>  #if TEST >= 2<br>
>  // expected-error@-2 {{redefinition of '}}<br>
>  // expected-note@-3 {{unguarded header; consider using #ifdef guards or #pragma once}}<br>
> -// expected-note-re@modules-ts.<wbr>cppm:1 {{'{{.*}}modules-ts.cppm' included multiple times, additional include site here}}<br>
> +// FIXME: We should drop the "header from" in this diagnostic.<br>
> +// expected-note-re@modules-ts.<wbr>cppm:1 {{'{{.*}}modules-ts.cppm' included multiple times, additional include site in header from module 'foo'}}<br>
>  #endif<br>
><br>
>  #if TEST == 0<br>
><br>
><br>
> ______________________________<wbr>_________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
<br>
<br>
<br>
</div></div><span class="HOEnZb"><font color="#888888">--<br>
Bruno Cardoso Lopes<br>
<a href="http://www.brunocardoso.cc" rel="noreferrer" target="_blank">http://www.brunocardoso.cc</a><br>
</font></span></blockquote></div><br></div></div>