diff options
Diffstat (limited to 'clang')
6 files changed, 44 insertions, 4 deletions
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 046c699a224..5b86c0a777d 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2547,6 +2547,20 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing, } } +/// ODR-like semantics for C/ObjC allow us to merge tag types and a structural +/// check in Sema guarantees the types can be merged (see C11 6.2.7/1 or C89 +/// 6.1.2.6/1). Although most merging is done in Sema, we need to guarantee +/// that some types are mergeable during deserialization, otherwise name +/// lookup fails. This is the case for EnumConstantDecl. +bool allowODRLikeMergeInC(NamedDecl *ND) { + if (!ND) + return false; + // TODO: implement merge for other necessary decls. + if (dyn_cast<EnumConstantDecl>(ND)) + return true; + return false; +} + /// \brief Attempts to merge the given declaration (D) with another declaration /// of the same entity, for the case where the entity is not actually /// redeclarable. This happens, for instance, when merging the fields of @@ -2557,10 +2571,12 @@ void ASTDeclReader::mergeMergeable(Mergeable<T> *D) { if (!Reader.getContext().getLangOpts().Modules) return; - // ODR-based merging is only performed in C++. In C, identically-named things - // in different translation units are not redeclarations (but may still have - // compatible types). - if (!Reader.getContext().getLangOpts().CPlusPlus) + // ODR-based merging is performed in C++ and in some cases (tag types) in C. + // Note that C identically-named things in different translation units are + // not redeclarations, but may still have compatible types, where ODR-like + // semantics may apply. + if (!Reader.getContext().getLangOpts().CPlusPlus && + !allowODRLikeMergeInC(dyn_cast<NamedDecl>(static_cast<T*>(D)))) return; if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D))) diff --git a/clang/test/Modules/Inputs/non-ambiguous-enum/A.framework/Headers/a.h b/clang/test/Modules/Inputs/non-ambiguous-enum/A.framework/Headers/a.h new file mode 100644 index 00000000000..060bc499738 --- /dev/null +++ b/clang/test/Modules/Inputs/non-ambiguous-enum/A.framework/Headers/a.h @@ -0,0 +1 @@ +#include <A/a0.h> diff --git a/clang/test/Modules/Inputs/non-ambiguous-enum/A.framework/Headers/a0.h b/clang/test/Modules/Inputs/non-ambiguous-enum/A.framework/Headers/a0.h new file mode 100644 index 00000000000..2e4d0912119 --- /dev/null +++ b/clang/test/Modules/Inputs/non-ambiguous-enum/A.framework/Headers/a0.h @@ -0,0 +1 @@ +#include <B/b.h> diff --git a/clang/test/Modules/Inputs/non-ambiguous-enum/A.framework/Modules/module.modulemap b/clang/test/Modules/Inputs/non-ambiguous-enum/A.framework/Modules/module.modulemap new file mode 100644 index 00000000000..d9a1981d53c --- /dev/null +++ b/clang/test/Modules/Inputs/non-ambiguous-enum/A.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ + +framework module A { + header "a.h" + //module * { export * } + export * +} diff --git a/clang/test/Modules/Inputs/non-ambiguous-enum/B.framework/Headers/b.h b/clang/test/Modules/Inputs/non-ambiguous-enum/B.framework/Headers/b.h new file mode 100644 index 00000000000..def44e3a634 --- /dev/null +++ b/clang/test/Modules/Inputs/non-ambiguous-enum/B.framework/Headers/b.h @@ -0,0 +1,6 @@ +typedef long NSInteger; +typedef enum __attribute__((flag_enum,enum_extensibility(open))) MyObjCEnum : NSInteger MyObjCEnum; + +enum MyObjCEnum : NSInteger { + MyEnumCst = 1, +} __attribute__((availability(ios,introduced=11.0))) __attribute__((availability(tvos,unavailable))) ; diff --git a/clang/test/Modules/non-ambiguous-enum.m b/clang/test/Modules/non-ambiguous-enum.m new file mode 100644 index 00000000000..f6d2a3ecb6d --- /dev/null +++ b/clang/test/Modules/non-ambiguous-enum.m @@ -0,0 +1,10 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -F%S/Inputs/non-ambiguous-enum -fsyntax-only %s -verify +#import <B/B.h> +#import <A/A.h> + +// expected-no-diagnostics + +int foo() { + return MyEnumCst; +} |