diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 34e4759a85f7f7f8002b30754f8151cfa104dcec..38599d6b1f50a526eea57b4af724eee4fd641bba 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -293,6 +293,9 @@ def warn_pp_macro_hides_keyword : Extension< def warn_pp_macro_is_reserved_id : Warning< "macro name is a reserved identifier">, DefaultIgnore, InGroup<ReservedIdAsMacro>; +def warn_pp_objc_macro_redef_ignored : Warning< + "ignoring redefinition of Objective-C qualifier macro">, + InGroup<DiagGroup<"objc-macro-redefinition">>; def pp_invalid_string_literal : Warning< "invalid string literal, ignoring final '\\'">; diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index fd16168203a99815ff13645c915fde04963bcd53..298543e2e95fc3a8bb7b8c0227969a827d598473 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -2266,6 +2266,30 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok, // Finally, if this identifier already had a macro defined for it, verify that // the macro bodies are identical, and issue diagnostics if they are not. if (const MacroInfo *OtherMI=getMacroInfo(MacroNameTok.getIdentifierInfo())) { + // In Objective-C, ignore attempts to directly redefine the builtin + // definitions of the ownership qualifiers. It's still possible to + // #undef them. + auto isObjCProtectedMacro = [](const IdentifierInfo *II) -> bool { + return II->isStr("__strong") || + II->isStr("__weak") || + II->isStr("__unsafe_unretained") || + II->isStr("__autoreleasing"); + }; + if (getLangOpts().ObjC1 && + SourceMgr.getFileID(OtherMI->getDefinitionLoc()) + == getPredefinesFileID() && + isObjCProtectedMacro(MacroNameTok.getIdentifierInfo())) { + // Warn if it changes the tokens. + if ((!getDiagnostics().getSuppressSystemWarnings() || + !SourceMgr.isInSystemHeader(DefineTok.getLocation())) && + !MI->isIdenticalTo(*OtherMI, *this, + /*Syntactic=*/LangOpts.MicrosoftExt)) { + Diag(MI->getDefinitionLoc(), diag::warn_pp_objc_macro_redef_ignored); + } + assert(!OtherMI->isWarnIfUnused()); + return; + } + // It is very common for system headers to have tons of macro redefinitions // and for warnings to be disabled in system headers. If this is the case, // then don't bother calling MacroInfo::isIdenticalTo. diff --git a/test/Lexer/objc_macros.m b/test/Lexer/objc_macros.m new file mode 100644 index 0000000000000000000000000000000000000000..0223bed4e3b0013f089146fb8e763bcdeeab9610 --- /dev/null +++ b/test/Lexer/objc_macros.m @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only "-triple" "x86_64-apple-macosx10.10.0" -fobjc-runtime-has-weak -fobjc-weak %s -verify %s + +#define __strong +// expected-warning@-1 {{ignoring redefinition of Objective-C qualifier macro}} +#define __weak +// expected-warning@-1 {{ignoring redefinition of Objective-C qualifier macro}} +#define __unsafe_unretained +// expected-warning@-1 {{ignoring redefinition of Objective-C qualifier macro}} +#define __autoreleased +// No warning because this is the default expansion anyway. + +// Check that this still expands to the right text. +void test() { + goto label; // expected-error {{cannot jump from this goto statement to its label}} + __weak id x; // expected-note {{jump bypasses initialization of __weak variable}} +label: + return; +} + +#undef __strong +#define __strong +// No warning.