On Fri, Oct 14, 2016 at 11:44 AM, Bruno Cardoso Lopes < bruno.card...@gmail.com> wrote:
> Hi Richard, > > I have a patch on top of your suggested patch from a year ago, that > break the cyclic dependency we're seeing, with this (and a few changes > to the SDK) we can bootstrap clang with submodule local visibility on > darwin. I've attached the patch with a reduced, standalone testcase > that doesn't depend on the SDK. The issues that are not covered by > your patch, that I cover in mine, are related to built-in and textual > headers: they can be found in paths where they don't map to any > modules, triggering other cycles. I fix that by looking further to > find a matching module for the header in question, instead the first > found header in header search. > It looks like the 0002 patch is working around a bug in the 0001 patch: with 0001 applied, a module with [no_undeclared_includes] can still include a textual header from another module on which it doesn't declare a dependency (in the testcase, the libc module is incorrectly permitted to include the textual header <stdio.h> from libc++). Rather than preferring non-modular headers over modular headers as the 0002 patch does, I wonder if the issue could instead be resolved by fixing that apparent bug. I gave that a go; the result is attached. I also had to change the way we handle builtin headers -- instead of implicitly including (for instance) the builtin <stddef.h> as a modular header in any module that provides its own <stddef.h>, I now only include it as a textual header (this also lets us use the same approach for this case whether or not we're using local submodule visibility). That exposed a couple of testcases that were (unreasonably, in my opinion) failing to include_next the real builtin header from their wrapper header. The attached patch causes your testcase to pass; I'd be interested to know if it works in practice on Darwin. Thanks! > Can you take a look? > > Thanks, > > > On Thu, Jul 28, 2016 at 3:55 PM, Adrian Prantl via cfe-commits > <cfe-commits@lists.llvm.org> wrote: > > +Bruno > > > > On Jul 27, 2016, at 11:58 PM, Nico Weber <tha...@chromium.org> wrote: > > > > I played with modules a bit today, and as far as I can tell this is still > > broken. If this proves difficult to fix, should this change be reverted > for > > now? It breaks using modules on Darwin. > > > > On Sun, Mar 13, 2016 at 12:53 AM, Adrian Prantl via cfe-commits > > <cfe-commits@lists.llvm.org> wrote: > >> > >> > On Mar 11, 2016, at 4:11 PM, Duncan P. N. Exon Smith > >> > <dexonsm...@apple.com> wrote: > >> > > >> > Did anyone file a PR for this? > >> > > >> > >> I filed PR 26928 - Prune the include path for modules > >> https://llvm.org/bugs/show_bug.cgi?id=26928 > >> as a starting point. > >> > >> -- adrian > >> > >> _______________________________________________ > >> cfe-commits mailing list > >> cfe-commits@lists.llvm.org > >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > > > > > > > > > > _______________________________________________ > > cfe-commits mailing list > > cfe-commits@lists.llvm.org > > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > > > > > > -- > Bruno Cardoso Lopes > http://www.brunocardoso.cc >
Index: include/clang/Basic/Module.h =================================================================== --- include/clang/Basic/Module.h (revision 284181) +++ include/clang/Basic/Module.h (working copy) @@ -201,6 +201,10 @@ /// built. unsigned ConfigMacrosExhaustive : 1; + /// \brief Whether files in this module can only include files from used + /// modules. + unsigned NoUndeclaredIncludes : 1; + /// \brief Describes the visibility of the various names within a /// particular module. enum NameVisibilityKind { Index: include/clang/Lex/HeaderSearch.h =================================================================== --- include/clang/Lex/HeaderSearch.h (revision 284181) +++ include/clang/Lex/HeaderSearch.h (working copy) @@ -523,8 +523,10 @@ /// \brief Retrieve the module that corresponds to the given file, if any. /// /// \param File The header that we wish to map to a module. - ModuleMap::KnownHeader findModuleForHeader(const FileEntry *File) const; - + /// \param AllowTextual Whether we want to find textual headers too. + ModuleMap::KnownHeader findModuleForHeader(const FileEntry *File, + bool AllowTextual = false) const; + /// \brief Read the contents of the given module map file. /// /// \param File The module map file. Index: include/clang/Lex/ModuleMap.h =================================================================== --- include/clang/Lex/ModuleMap.h (revision 284181) +++ include/clang/Lex/ModuleMap.h (working copy) @@ -171,7 +171,8 @@ /// \brief The set of attributes that can be attached to a module. struct Attributes { - Attributes() : IsSystem(), IsExternC(), IsExhaustive() {} + Attributes() + : IsSystem(), IsExternC(), IsExhaustive(), NoUndeclaredIncludes() {} /// \brief Whether this is a system module. unsigned IsSystem : 1; @@ -181,6 +182,10 @@ /// \brief Whether this is an exhaustive set of configuration macros. unsigned IsExhaustive : 1; + + /// \brief Whether files in this module can only include files from + /// explicit dependencies of the module. + unsigned NoUndeclaredIncludes : 1; }; /// \brief A directory for which framework modules can be inferred. @@ -315,10 +320,15 @@ /// /// \param File The header file that is likely to be included. /// + /// \param AllowTextual If \c true and \p File is a textual header, return + /// its owning module. Otherwise, no KnownHeader will be returned if the + /// file is only known as a textual header. + /// /// \returns The module KnownHeader, which provides the module that owns the /// given header file. The KnownHeader is default constructed to indicate /// that no module owns this header file. - KnownHeader findModuleForHeader(const FileEntry *File); + KnownHeader findModuleForHeader(const FileEntry *File, + bool AllowTextual = false); /// \brief Retrieve all the modules that contain the given header file. This /// may not include umbrella modules, nor information from external sources, Index: lib/Basic/Module.cpp =================================================================== --- lib/Basic/Module.cpp (revision 284181) +++ lib/Basic/Module.cpp (working copy) @@ -33,7 +33,7 @@ IsExplicit(IsExplicit), IsSystem(false), IsExternC(false), IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false), InferExportWildcard(false), ConfigMacrosExhaustive(false), - NameVisibility(Hidden) { + NoUndeclaredIncludes(false), NameVisibility(Hidden) { if (Parent) { if (!Parent->isAvailable()) IsAvailable = false; @@ -41,6 +41,8 @@ IsSystem = true; if (Parent->IsExternC) IsExternC = true; + if (Parent->NoUndeclaredIncludes) + NoUndeclaredIncludes = true; IsMissingRequirement = Parent->IsMissingRequirement; Parent->SubModuleIndex[Name] = Parent->SubModules.size(); @@ -181,6 +183,11 @@ for (auto *Use : Top->DirectUses) if (Requested->isSubModuleOf(Use)) return true; + + // Anyone is allowed to use our builtin stddef.h and its accompanying module. + if (!Requested->Parent && Requested->Name == "_Builtin_stddef_max_align_t") + return true; + return false; } Index: lib/Lex/HeaderSearch.cpp =================================================================== --- lib/Lex/HeaderSearch.cpp (revision 284181) +++ lib/Lex/HeaderSearch.cpp (working copy) @@ -413,6 +413,12 @@ return TopFrameworkDir; } +static bool needModuleLookup(Module *RequestingModule, + bool HasSuggestedModule) { + return HasSuggestedModule || + (RequestingModule && RequestingModule->NoUndeclaredIncludes); +} + /// DoFrameworkLookup - Do a lookup of the specified file in the current /// DirectoryLookup, which is a framework directory. const FileEntry *DirectoryLookup::DoFrameworkLookup( @@ -508,7 +514,7 @@ } // If we found the header and are allowed to suggest a module, do so now. - if (FE && SuggestedModule) { + if (FE && needModuleLookup(RequestingModule, SuggestedModule)) { // Find the framework in which this header occurs. StringRef FrameworkPath = FE->getDir()->getName(); bool FoundFramework = false; @@ -1158,22 +1164,45 @@ } ModuleMap::KnownHeader -HeaderSearch::findModuleForHeader(const FileEntry *File) const { +HeaderSearch::findModuleForHeader(const FileEntry *File, + bool AllowTextual) const { if (ExternalSource) { // Make sure the external source has handled header info about this file, // which includes whether the file is part of a module. (void)getExistingFileInfo(File); } - return ModMap.findModuleForHeader(File); + return ModMap.findModuleForHeader(File, AllowTextual); } +static bool suggestModule(HeaderSearch &HS, const FileEntry *File, + Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule) { + ModuleMap::KnownHeader Module = + HS.findModuleForHeader(File, /*AllowTextual*/true); + if (SuggestedModule) + *SuggestedModule = (Module.getRole() & ModuleMap::TextualHeader) + ? ModuleMap::KnownHeader() + : Module; + + // If this module specifies [no_undeclared_includes], we cannot find any + // file that's in a non-dependency module. + if (RequestingModule && Module && RequestingModule->NoUndeclaredIncludes) { + HS.getModuleMap().resolveUses(RequestingModule, /*Complain*/false); + if (!RequestingModule->directlyUses(Module.getModule())) { + return false; + } + } + + return true; +} + bool HeaderSearch::findUsableModuleForHeader( const FileEntry *File, const DirectoryEntry *Root, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, bool IsSystemHeaderDir) { - if (File && SuggestedModule) { + if (File && needModuleLookup(RequestingModule, SuggestedModule)) { // If there is a module that corresponds to this header, suggest it. hasModuleMap(File->getName(), Root, IsSystemHeaderDir); - *SuggestedModule = findModuleForHeader(File); + return suggestModule(*this, File, RequestingModule, SuggestedModule); } return true; } @@ -1182,7 +1211,7 @@ const FileEntry *File, StringRef FrameworkName, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, bool IsSystemFramework) { // If we're supposed to suggest a module, look for one now. - if (SuggestedModule) { + if (needModuleLookup(RequestingModule, SuggestedModule)) { // Find the top-level framework based on this framework. SmallVector<std::string, 4> SubmodulePath; const DirectoryEntry *TopFrameworkDir @@ -1199,7 +1228,7 @@ // important so that we're consistent about whether this header // corresponds to a module. Possibly we should lock down framework modules // so that this is not possible. - *SuggestedModule = findModuleForHeader(File); + return suggestModule(*this, File, RequestingModule, SuggestedModule); } return true; } Index: lib/Lex/ModuleMap.cpp =================================================================== --- lib/Lex/ModuleMap.cpp (revision 284181) +++ lib/Lex/ModuleMap.cpp (working copy) @@ -327,9 +327,10 @@ return false; } -ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File) { +ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File, + bool AllowTextual) { auto MakeResult = [&](ModuleMap::KnownHeader R) -> ModuleMap::KnownHeader { - if (R.getRole() & ModuleMap::TextualHeader) + if (!AllowTextual && R.getRole() & ModuleMap::TextualHeader) return ModuleMap::KnownHeader(); return R; }; @@ -674,6 +675,8 @@ Attrs.IsSystem |= inferred->second.Attrs.IsSystem; Attrs.IsExternC |= inferred->second.Attrs.IsExternC; Attrs.IsExhaustive |= inferred->second.Attrs.IsExhaustive; + Attrs.NoUndeclaredIncludes |= + inferred->second.Attrs.NoUndeclaredIncludes; ModuleMapFile = inferred->second.ModuleMapFile; } } @@ -711,6 +714,7 @@ Result->IsSystem |= Attrs.IsSystem; Result->IsExternC |= Attrs.IsExternC; Result->ConfigMacrosExhaustive |= Attrs.IsExhaustive; + Result->NoUndeclaredIncludes |= Attrs.NoUndeclaredIncludes; Result->Directory = FrameworkDir; // umbrella header "umbrella-header-name" @@ -1309,7 +1313,9 @@ /// \brief The 'extern_c' attribute. AT_extern_c, /// \brief The 'exhaustive' attribute. - AT_exhaustive + AT_exhaustive, + /// \brief The 'no_undeclared_includes' attribute. + AT_no_undeclared_includes }; } @@ -1479,6 +1485,9 @@ ActiveModule->IsSystem = true; if (Attrs.IsExternC) ActiveModule->IsExternC = true; + if (Attrs.NoUndeclaredIncludes || + (!ActiveModule->Parent && ModuleName == "Darwin")) + ActiveModule->NoUndeclaredIncludes = true; ActiveModule->Directory = Directory; bool Done = false; @@ -1845,13 +1854,7 @@ // If Clang supplies this header but the underlying system does not, // just silently swap in our builtin version. Otherwise, we'll end // up adding both (later). - // - // For local visibility, entirely replace the system file with our - // one and textually include the system one. We need to pass macros - // from our header to the system one if we #include_next it. - // - // FIXME: Can we do this in all cases? - if (BuiltinFile && (!File || Map.LangOpts.ModulesLocalVisibility)) { + if (BuiltinFile && !File) { File = BuiltinFile; RelativePathName = BuiltinPathName; BuiltinFile = nullptr; @@ -1877,15 +1880,16 @@ Module::Header H = {RelativePathName.str(), File}; Map.excludeHeader(ActiveModule, H); } else { - // If there is a builtin counterpart to this file, add it now, before - // the "real" header, so we build the built-in one first when building - // the module. + // If there is a builtin counterpart to this file, add it now as a textual + // header, so it can be #include_next'd by the wrapper header, and can + // receive macros from the wrapper header. if (BuiltinFile) { // FIXME: Taking the name from the FileEntry is unstable and can give // different results depending on how we've previously named that file // in this build. Module::Header H = { BuiltinFile->getName(), BuiltinFile }; - Map.addHeader(ActiveModule, H, Role); + Map.addHeader(ActiveModule, H, ModuleMap::ModuleHeaderRole( + Role | ModuleMap::TextualHeader)); } // Record this header. @@ -2375,6 +2379,7 @@ = llvm::StringSwitch<AttributeKind>(Tok.getString()) .Case("exhaustive", AT_exhaustive) .Case("extern_c", AT_extern_c) + .Case("no_undeclared_includes", AT_no_undeclared_includes) .Case("system", AT_system) .Default(AT_unknown); switch (Attribute) { @@ -2394,6 +2399,10 @@ case AT_exhaustive: Attrs.IsExhaustive = true; break; + + case AT_no_undeclared_includes: + Attrs.NoUndeclaredIncludes = true; + break; } consumeToken(); Index: test/Modules/Inputs/System/usr/include/stdbool.h =================================================================== --- test/Modules/Inputs/System/usr/include/stdbool.h (revision 284181) +++ test/Modules/Inputs/System/usr/include/stdbool.h (working copy) @@ -1 +1 @@ -// Testing hack: does not define bool/true/false. +#include_next <stdbool.h> Index: test/Modules/Inputs/libc-libcxx/include/c++/math.h =================================================================== --- test/Modules/Inputs/libc-libcxx/include/c++/math.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/include/c++/math.h (working copy) @@ -0,0 +1,2 @@ +#include_next <math.h> +template<typename T> T abs(T t) { return (t < 0) ? -t : t; } Index: test/Modules/Inputs/libc-libcxx/include/c++/module.modulemap =================================================================== --- test/Modules/Inputs/libc-libcxx/include/c++/module.modulemap (revision 0) +++ test/Modules/Inputs/libc-libcxx/include/c++/module.modulemap (working copy) @@ -0,0 +1,4 @@ +module "libc++" { + module math { header "math.h" export * } + module stdlib { header "stdlib.h" export * } +} Index: test/Modules/Inputs/libc-libcxx/include/c++/stdlib.h =================================================================== --- test/Modules/Inputs/libc-libcxx/include/c++/stdlib.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/include/c++/stdlib.h (working copy) @@ -0,0 +1 @@ +#include_next "stdlib.h" Index: test/Modules/Inputs/libc-libcxx/include/math.h =================================================================== --- test/Modules/Inputs/libc-libcxx/include/math.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/include/math.h (working copy) @@ -0,0 +1 @@ +int abs(int); Index: test/Modules/Inputs/libc-libcxx/include/module.modulemap =================================================================== --- test/Modules/Inputs/libc-libcxx/include/module.modulemap (revision 0) +++ test/Modules/Inputs/libc-libcxx/include/module.modulemap (working copy) @@ -0,0 +1,4 @@ +module libc [no_undeclared_includes] { + module math { header "math.h" export * } + module stdlib { header "stdlib.h" export * } +} Index: test/Modules/Inputs/libc-libcxx/include/stdlib.h =================================================================== --- test/Modules/Inputs/libc-libcxx/include/stdlib.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/include/stdlib.h (working copy) @@ -0,0 +1 @@ +#include <math.h> Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/__config =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/__config (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/__config (working copy) @@ -0,0 +1,6 @@ +#ifndef _LIBCPP_CONFIG +#define _LIBCPP_CONFIG + +#define __LIBCXX_CONFIG + +#endif Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/math.h =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/math.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/math.h (working copy) @@ -0,0 +1,7 @@ +#ifndef LIBCXX_MATH_H +#define LIBCXX_MATH_H + +#include_next <math.h> +template<typename T> T abs(T t) { return (t < 0) ? -t : t; } + +#endif Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/module.modulemap =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/module.modulemap (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/module.modulemap (working copy) @@ -0,0 +1,7 @@ +module "libc++" { + module math { header "math.h" export * } + module stdlib { header "stdlib.h" export * } + module stddef { header "stddef.h" export * } + module stdio { textual header "stdio.h" export * } + module __config { header "__config" export * } +} Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stddef.h =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stddef.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stddef.h (working copy) @@ -0,0 +1,6 @@ +#ifndef LIBCXX_STDDEF_H +#define LIBCXX_STDDEF_H + +#include <__config> + +#endif Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stdio.h =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stdio.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stdio.h (working copy) @@ -0,0 +1,6 @@ +#ifndef LIBCXX_STDIO_H +#define LIBCXX_STDIO_H + +#include <__config> + +#endif Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stdlib.h =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stdlib.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stdlib.h (working copy) @@ -0,0 +1,6 @@ +#ifndef LIBCXX_STDLIB_H +#define LIBCXX_STDLIB_H + +#include_next "stdlib.h" + +#endif Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/math.h =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/math.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/math.h (working copy) @@ -0,0 +1 @@ +int abs(int); Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/module.modulemap =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/module.modulemap (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/module.modulemap (working copy) @@ -0,0 +1,9 @@ +module libc [no_undeclared_includes] { + module math { header "math.h" export * } + module stdlib { header "stdlib.h" export * } + module stdatomic { header "stdatomic.h" export * } + module stddef { header "stddef.h" export * } + module stdint { header "stdint.h" export * } + module stdio { header "stdio.h" export * } + module util { header "util.h" export * } +} Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stddef.h =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stddef.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stddef.h (working copy) @@ -0,0 +1,2 @@ +// stddef.h +#include_next "stddef.h" Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stdint.h =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stdint.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stdint.h (working copy) @@ -0,0 +1,22 @@ +typedef char int_least8_t; +typedef short int_least16_t; +typedef int int_least32_t; +typedef long long int int_least64_t; +typedef unsigned char uint_least8_t; +typedef unsigned short uint_least16_t; +typedef unsigned int uint_least32_t; +typedef unsigned long long uint_least64_t; + +typedef char int_fast8_t; +typedef short int_fast16_t; +typedef int int_fast32_t; +typedef long long int int_fast64_t; +typedef unsigned char uint_fast8_t; +typedef unsigned short uint_fast16_t; +typedef unsigned int uint_fast32_t; +typedef unsigned long long uint_fast64_t; + +typedef int * intptr_t; +typedef unsigned int * uintptr_t; +typedef int intmax_t; +typedef unsigned int uintmax_t; Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stdio.h =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stdio.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stdio.h (working copy) @@ -0,0 +1,4 @@ +#ifndef DARWIN_STDIO_H +#define DARWIN_STDIO_H + +#endif Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stdlib.h =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stdlib.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stdlib.h (working copy) @@ -0,0 +1 @@ +#include <math.h> Index: test/Modules/Inputs/libc-libcxx/sysroot/usr/include/util.h =================================================================== --- test/Modules/Inputs/libc-libcxx/sysroot/usr/include/util.h (revision 0) +++ test/Modules/Inputs/libc-libcxx/sysroot/usr/include/util.h (working copy) @@ -0,0 +1,6 @@ +#ifndef DARWIN_UTIL_H +#define DARWIN_UTIL_H + +#include <stdio.h> + +#endif Index: test/Modules/libc-libcxx.cpp =================================================================== --- test/Modules/libc-libcxx.cpp (revision 0) +++ test/Modules/libc-libcxx.cpp (working copy) @@ -0,0 +1,10 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -x c++ -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/libc-libcxx/include/c++ -I %S/Inputs/libc-libcxx/include %s -verify +// RUN: rm -rf %t +// RUN: %clang_cc1 -x c++ -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -fmodules-local-submodule-visibility -nostdinc++ -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -isystem %S/Inputs/libc-libcxx/sysroot/usr/include -fsyntax-only %s -verify +// expected-no-diagnostics + +#include "math.h" + +int n = abs(0); +float f = abs<float>(0.f);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits