forked from OSchip/llvm-project
Implement #pragma clang final extension
This patch adds a new preprocessor extension ``#pragma clang final`` which enables warning on undefinition and re-definition of macros. The intent of this warning is to extend beyond ``-Wmacro-redefined`` to warn against any and all alterations to macros that are marked `final`. This warning is part of the ``-Wpedantic-macros`` diagnostics group. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D108567
This commit is contained in:
parent
fdba1dccbe
commit
1e48ef2035
|
@ -3944,6 +3944,24 @@ will expansion of the macro within the main source file. For example:
|
||||||
|
|
||||||
This warning is controlled by ``-Wpedantic-macros``.
|
This warning is controlled by ``-Wpedantic-macros``.
|
||||||
|
|
||||||
|
Final Macros
|
||||||
|
============
|
||||||
|
|
||||||
|
Clang supports the pragma ``#pragma clang final``, which can be used to
|
||||||
|
mark macros as final, meaning they cannot be undef'd or re-defined. For example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
#define FINAL_MACRO 1
|
||||||
|
#pragma clang final(FINAL_MACRO)
|
||||||
|
|
||||||
|
#define FINAL_MACRO // warning: FINAL_MACRO is marked final and should not be redefined
|
||||||
|
#undef FINAL_MACRO // warning: FINAL_MACRO is marked final and should not be undefined
|
||||||
|
|
||||||
|
This is useful for enforcing system-provided macros that should not be altered
|
||||||
|
in user headers or code. This is controlled by ``-Wpedantic-macros``. Final
|
||||||
|
macros will always warn on redefinition, including situations with identical
|
||||||
|
bodies and in system headers.
|
||||||
|
|
||||||
Extended Integer Types
|
Extended Integer Types
|
||||||
======================
|
======================
|
||||||
|
|
||||||
|
|
|
@ -648,6 +648,7 @@ def KeywordAsMacro : DiagGroup<"keyword-macro">;
|
||||||
def ReservedIdAsMacro : DiagGroup<"reserved-macro-identifier">;
|
def ReservedIdAsMacro : DiagGroup<"reserved-macro-identifier">;
|
||||||
def ReservedIdAsMacroAlias : DiagGroup<"reserved-id-macro", [ReservedIdAsMacro]>;
|
def ReservedIdAsMacroAlias : DiagGroup<"reserved-id-macro", [ReservedIdAsMacro]>;
|
||||||
def RestrictExpansionMacro : DiagGroup<"restrict-expansion">;
|
def RestrictExpansionMacro : DiagGroup<"restrict-expansion">;
|
||||||
|
def FinalMacro : DiagGroup<"final-macro">;
|
||||||
|
|
||||||
// Just silence warnings about -Wstrict-aliasing for now.
|
// Just silence warnings about -Wstrict-aliasing for now.
|
||||||
def : DiagGroup<"strict-aliasing=0">;
|
def : DiagGroup<"strict-aliasing=0">;
|
||||||
|
@ -1322,4 +1323,5 @@ def PedanticMacros : DiagGroup<"pedantic-macros",
|
||||||
[DeprecatedPragma,
|
[DeprecatedPragma,
|
||||||
MacroRedefined,
|
MacroRedefined,
|
||||||
BuiltinMacroRedefined,
|
BuiltinMacroRedefined,
|
||||||
RestrictExpansionMacro]>;
|
RestrictExpansionMacro,
|
||||||
|
FinalMacro]>;
|
||||||
|
|
|
@ -551,7 +551,13 @@ def warn_pragma_restrict_expansion_macro_use :
|
||||||
|
|
||||||
// - Note for macro annotations.
|
// - Note for macro annotations.
|
||||||
def note_pp_macro_annotation :
|
def note_pp_macro_annotation :
|
||||||
Note<"macro marked '%select{deprecated|restrict_expansion}0' here">;
|
Note<"macro marked '%select{deprecated|restrict_expansion|final}0' here">;
|
||||||
|
|
||||||
|
// - #pragma clang final(...)
|
||||||
|
def warn_pragma_final_macro :
|
||||||
|
ExtWarn<"macro %0 has been marked as final and should not be "
|
||||||
|
"%select{undefined|redefined}1">,
|
||||||
|
InGroup<FinalMacro>;
|
||||||
|
|
||||||
// - #pragma execution_character_set(...)
|
// - #pragma execution_character_set(...)
|
||||||
def warn_pragma_exec_charset_expected :
|
def warn_pragma_exec_charset_expected :
|
||||||
|
|
|
@ -127,7 +127,10 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
|
||||||
// True if this macro is unsafe in headers.
|
// True if this macro is unsafe in headers.
|
||||||
unsigned IsRestrictExpansion : 1;
|
unsigned IsRestrictExpansion : 1;
|
||||||
|
|
||||||
// 23 bits left in a 64-bit word.
|
// True if this macro is final.
|
||||||
|
unsigned IsFinal : 1;
|
||||||
|
|
||||||
|
// 22 bits left in a 64-bit word.
|
||||||
|
|
||||||
// Managed by the language front-end.
|
// Managed by the language front-end.
|
||||||
void *FETokenInfo = nullptr;
|
void *FETokenInfo = nullptr;
|
||||||
|
@ -141,7 +144,7 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
|
||||||
NeedsHandleIdentifier(false), IsFromAST(false), ChangedAfterLoad(false),
|
NeedsHandleIdentifier(false), IsFromAST(false), ChangedAfterLoad(false),
|
||||||
FEChangedAfterLoad(false), RevertedTokenID(false), OutOfDate(false),
|
FEChangedAfterLoad(false), RevertedTokenID(false), OutOfDate(false),
|
||||||
IsModulesImport(false), IsMangledOpenMPVariantName(false),
|
IsModulesImport(false), IsMangledOpenMPVariantName(false),
|
||||||
IsDeprecatedMacro(false), IsRestrictExpansion(false) {}
|
IsDeprecatedMacro(false), IsRestrictExpansion(false), IsFinal(false) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IdentifierInfo(const IdentifierInfo &) = delete;
|
IdentifierInfo(const IdentifierInfo &) = delete;
|
||||||
|
@ -189,10 +192,14 @@ public:
|
||||||
NeedsHandleIdentifier = true;
|
NeedsHandleIdentifier = true;
|
||||||
HadMacro = true;
|
HadMacro = true;
|
||||||
} else {
|
} else {
|
||||||
|
// If this is a final macro, make the deprecation and header unsafe bits
|
||||||
|
// stick around after the undefinition so they apply to any redefinitions.
|
||||||
|
if (!IsFinal) {
|
||||||
// Because calling the setters of these calls recomputes, just set them
|
// Because calling the setters of these calls recomputes, just set them
|
||||||
// manually to avoid recomputing a bunch of times.
|
// manually to avoid recomputing a bunch of times.
|
||||||
IsDeprecatedMacro = false;
|
IsDeprecatedMacro = false;
|
||||||
IsRestrictExpansion = false;
|
IsRestrictExpansion = false;
|
||||||
|
}
|
||||||
RecomputeNeedsHandleIdentifier();
|
RecomputeNeedsHandleIdentifier();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,6 +234,10 @@ public:
|
||||||
RecomputeNeedsHandleIdentifier();
|
RecomputeNeedsHandleIdentifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isFinal() const { return IsFinal; }
|
||||||
|
|
||||||
|
void setIsFinal(bool Val) { IsFinal = Val; }
|
||||||
|
|
||||||
/// If this is a source-language token (e.g. 'for'), this API
|
/// If this is a source-language token (e.g. 'for'), this API
|
||||||
/// can be used to cause the lexer to map identifiers to source-language
|
/// can be used to cause the lexer to map identifiers to source-language
|
||||||
/// tokens.
|
/// tokens.
|
||||||
|
|
|
@ -793,12 +793,35 @@ private:
|
||||||
/// annotation pragma for use producing diagnostics and notes.
|
/// annotation pragma for use producing diagnostics and notes.
|
||||||
using MsgLocationPair = std::pair<std::string, SourceLocation>;
|
using MsgLocationPair = std::pair<std::string, SourceLocation>;
|
||||||
|
|
||||||
/// Deprecation messages for macros provided in #pragma clang deprecated.
|
struct MacroAnnotationInfo {
|
||||||
llvm::DenseMap<const IdentifierInfo *, std::string> MacroDeprecationMsgs;
|
SourceLocation Location;
|
||||||
|
std::string Message;
|
||||||
|
};
|
||||||
|
|
||||||
/// Usage warning for macros marked by #pragma clang restrict_expansion.
|
struct MacroAnnotations {
|
||||||
llvm::DenseMap<const IdentifierInfo *, MsgLocationPair>
|
llvm::Optional<MacroAnnotationInfo> DeprecationInfo;
|
||||||
RestrictExpansionMacroMsgs;
|
llvm::Optional<MacroAnnotationInfo> RestrictExpansionInfo;
|
||||||
|
llvm::Optional<SourceLocation> FinalAnnotationLoc;
|
||||||
|
|
||||||
|
static MacroAnnotations makeDeprecation(SourceLocation Loc,
|
||||||
|
std::string Msg) {
|
||||||
|
return MacroAnnotations{MacroAnnotationInfo{Loc, std::move(Msg)},
|
||||||
|
llvm::None, llvm::None};
|
||||||
|
}
|
||||||
|
|
||||||
|
static MacroAnnotations makeRestrictExpansion(SourceLocation Loc,
|
||||||
|
std::string Msg) {
|
||||||
|
return MacroAnnotations{
|
||||||
|
llvm::None, MacroAnnotationInfo{Loc, std::move(Msg)}, llvm::None};
|
||||||
|
}
|
||||||
|
|
||||||
|
static MacroAnnotations makeFinal(SourceLocation Loc) {
|
||||||
|
return MacroAnnotations{llvm::None, llvm::None, Loc};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Warning information for macro annotations.
|
||||||
|
llvm::DenseMap<const IdentifierInfo *, MacroAnnotations> AnnotationInfos;
|
||||||
|
|
||||||
/// A "freelist" of MacroArg objects that can be
|
/// A "freelist" of MacroArg objects that can be
|
||||||
/// reused for quick allocation.
|
/// reused for quick allocation.
|
||||||
|
@ -2402,39 +2425,56 @@ public:
|
||||||
/// warnings.
|
/// warnings.
|
||||||
void markMacroAsUsed(MacroInfo *MI);
|
void markMacroAsUsed(MacroInfo *MI);
|
||||||
|
|
||||||
void addMacroDeprecationMsg(const IdentifierInfo *II, std::string Msg) {
|
void addMacroDeprecationMsg(const IdentifierInfo *II, std::string Msg,
|
||||||
MacroDeprecationMsgs.insert(std::make_pair(II, Msg));
|
SourceLocation AnnotationLoc) {
|
||||||
}
|
auto Annotations = AnnotationInfos.find(II);
|
||||||
|
if (Annotations == AnnotationInfos.end())
|
||||||
llvm::Optional<std::string> getMacroDeprecationMsg(const IdentifierInfo *II) {
|
AnnotationInfos.insert(std::make_pair(
|
||||||
auto MsgEntry = MacroDeprecationMsgs.find(II);
|
II,
|
||||||
if (MsgEntry == MacroDeprecationMsgs.end())
|
MacroAnnotations::makeDeprecation(AnnotationLoc, std::move(Msg))));
|
||||||
return llvm::None;
|
else
|
||||||
return MsgEntry->second;
|
Annotations->second.DeprecationInfo =
|
||||||
|
MacroAnnotationInfo{AnnotationLoc, std::move(Msg)};
|
||||||
}
|
}
|
||||||
|
|
||||||
void addRestrictExpansionMsg(const IdentifierInfo *II, std::string Msg,
|
void addRestrictExpansionMsg(const IdentifierInfo *II, std::string Msg,
|
||||||
SourceLocation AnnotationLoc) {
|
SourceLocation AnnotationLoc) {
|
||||||
RestrictExpansionMacroMsgs.insert(
|
auto Annotations = AnnotationInfos.find(II);
|
||||||
std::make_pair(II, std::make_pair(std::move(Msg), AnnotationLoc)));
|
if (Annotations == AnnotationInfos.end())
|
||||||
|
AnnotationInfos.insert(
|
||||||
|
std::make_pair(II, MacroAnnotations::makeRestrictExpansion(
|
||||||
|
AnnotationLoc, std::move(Msg))));
|
||||||
|
else
|
||||||
|
Annotations->second.RestrictExpansionInfo =
|
||||||
|
MacroAnnotationInfo{AnnotationLoc, std::move(Msg)};
|
||||||
}
|
}
|
||||||
|
|
||||||
MsgLocationPair getRestrictExpansionMsg(const IdentifierInfo *II) {
|
void addFinalLoc(const IdentifierInfo *II, SourceLocation AnnotationLoc) {
|
||||||
return RestrictExpansionMacroMsgs.find(II)->second;
|
auto Annotations = AnnotationInfos.find(II);
|
||||||
|
if (Annotations == AnnotationInfos.end())
|
||||||
|
AnnotationInfos.insert(
|
||||||
|
std::make_pair(II, MacroAnnotations::makeFinal(AnnotationLoc)));
|
||||||
|
else
|
||||||
|
Annotations->second.FinalAnnotationLoc = AnnotationLoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitMacroExpansionWarnings(const Token &Identifier) {
|
const MacroAnnotations &getMacroAnnotations(const IdentifierInfo *II) const {
|
||||||
|
return AnnotationInfos.find(II)->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitMacroExpansionWarnings(const Token &Identifier) const {
|
||||||
if (Identifier.getIdentifierInfo()->isDeprecatedMacro())
|
if (Identifier.getIdentifierInfo()->isDeprecatedMacro())
|
||||||
emitMacroDeprecationWarning(Identifier);
|
emitMacroDeprecationWarning(Identifier);
|
||||||
|
|
||||||
if (Identifier.getIdentifierInfo()->isRestrictExpansion() &&
|
if (Identifier.getIdentifierInfo()->isRestrictExpansion() &&
|
||||||
!SourceMgr.isInMainFile(Identifier.getLocation()))
|
!SourceMgr.isInMainFile(Identifier.getLocation()))
|
||||||
emitMacroUnsafeHeaderWarning(Identifier);
|
emitRestrictExpansionWarning(Identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void emitMacroDeprecationWarning(const Token &Identifier);
|
void emitMacroDeprecationWarning(const Token &Identifier) const;
|
||||||
void emitMacroUnsafeHeaderWarning(const Token &Identifier);
|
void emitRestrictExpansionWarning(const Token &Identifier) const;
|
||||||
|
void emitFinalMacroWarning(const Token &Identifier, bool IsUndef) const;
|
||||||
|
|
||||||
Optional<unsigned>
|
Optional<unsigned>
|
||||||
getSkippedRangeForExcludedConditionalBlock(SourceLocation HashLoc);
|
getSkippedRangeForExcludedConditionalBlock(SourceLocation HashLoc);
|
||||||
|
|
|
@ -2865,6 +2865,12 @@ void Preprocessor::HandleDefineDirective(
|
||||||
if (MacroNameTok.is(tok::eod))
|
if (MacroNameTok.is(tok::eod))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
|
||||||
|
// Issue a final pragma warning if we're defining a macro that was has been
|
||||||
|
// undefined and is being redefined.
|
||||||
|
if (!II->hasMacroDefinition() && II->hadMacroDefinition() && II->isFinal())
|
||||||
|
emitFinalMacroWarning(MacroNameTok, /*IsUndef=*/false);
|
||||||
|
|
||||||
// If we are supposed to keep comments in #defines, reenable comment saving
|
// If we are supposed to keep comments in #defines, reenable comment saving
|
||||||
// mode.
|
// mode.
|
||||||
if (CurLexer) CurLexer->SetCommentRetentionState(KeepMacroComments);
|
if (CurLexer) CurLexer->SetCommentRetentionState(KeepMacroComments);
|
||||||
|
@ -2907,6 +2913,12 @@ void Preprocessor::HandleDefineDirective(
|
||||||
// Finally, if this identifier already had a macro defined for it, verify that
|
// 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.
|
// the macro bodies are identical, and issue diagnostics if they are not.
|
||||||
if (const MacroInfo *OtherMI=getMacroInfo(MacroNameTok.getIdentifierInfo())) {
|
if (const MacroInfo *OtherMI=getMacroInfo(MacroNameTok.getIdentifierInfo())) {
|
||||||
|
// Final macros are hard-mode: they always warn. Even if the bodies are
|
||||||
|
// identical. Even if they are in system headers. Even if they are things we
|
||||||
|
// would silently allow in the past.
|
||||||
|
if (MacroNameTok.getIdentifierInfo()->isFinal())
|
||||||
|
emitFinalMacroWarning(MacroNameTok, /*IsUndef=*/false);
|
||||||
|
|
||||||
// In Objective-C, ignore attempts to directly redefine the builtin
|
// In Objective-C, ignore attempts to directly redefine the builtin
|
||||||
// definitions of the ownership qualifiers. It's still possible to
|
// definitions of the ownership qualifiers. It's still possible to
|
||||||
// #undef them.
|
// #undef them.
|
||||||
|
@ -2936,6 +2948,7 @@ void Preprocessor::HandleDefineDirective(
|
||||||
// then don't bother calling MacroInfo::isIdenticalTo.
|
// then don't bother calling MacroInfo::isIdenticalTo.
|
||||||
if (!getDiagnostics().getSuppressSystemWarnings() ||
|
if (!getDiagnostics().getSuppressSystemWarnings() ||
|
||||||
!SourceMgr.isInSystemHeader(DefineTok.getLocation())) {
|
!SourceMgr.isInSystemHeader(DefineTok.getLocation())) {
|
||||||
|
|
||||||
if (!OtherMI->isUsed() && OtherMI->isWarnIfUnused())
|
if (!OtherMI->isUsed() && OtherMI->isWarnIfUnused())
|
||||||
Diag(OtherMI->getDefinitionLoc(), diag::pp_macro_not_used);
|
Diag(OtherMI->getDefinitionLoc(), diag::pp_macro_not_used);
|
||||||
|
|
||||||
|
@ -3013,6 +3026,9 @@ void Preprocessor::HandleUndefDirective() {
|
||||||
auto MD = getMacroDefinition(II);
|
auto MD = getMacroDefinition(II);
|
||||||
UndefMacroDirective *Undef = nullptr;
|
UndefMacroDirective *Undef = nullptr;
|
||||||
|
|
||||||
|
if (II->isFinal())
|
||||||
|
emitFinalMacroWarning(MacroNameTok, /*IsUndef=*/true);
|
||||||
|
|
||||||
// If the macro is not defined, this is a noop undef.
|
// If the macro is not defined, this is a noop undef.
|
||||||
if (const MacroInfo *MI = MD.getMacroInfo()) {
|
if (const MacroInfo *MI = MD.getMacroInfo()) {
|
||||||
if (!MI->isUsed() && MI->isWarnIfUnused())
|
if (!MI->isUsed() && MI->isWarnIfUnused())
|
||||||
|
|
|
@ -1990,7 +1990,7 @@ static IdentifierInfo *HandleMacroAnnotationPragma(Preprocessor &PP, Token &Tok,
|
||||||
IdentifierInfo *II = Tok.getIdentifierInfo();
|
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||||
|
|
||||||
if (!II->hasMacroDefinition()) {
|
if (!II->hasMacroDefinition()) {
|
||||||
PP.Diag(Tok, diag::err_pp_visibility_non_macro) << II->getName();
|
PP.Diag(Tok, diag::err_pp_visibility_non_macro) << II;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2025,8 +2025,8 @@ struct PragmaDeprecatedHandler : public PragmaHandler {
|
||||||
if (IdentifierInfo *II = HandleMacroAnnotationPragma(
|
if (IdentifierInfo *II = HandleMacroAnnotationPragma(
|
||||||
PP, Tok, "#pragma clang deprecated", MessageString)) {
|
PP, Tok, "#pragma clang deprecated", MessageString)) {
|
||||||
II->setIsDeprecatedMacro(true);
|
II->setIsDeprecatedMacro(true);
|
||||||
if (!MessageString.empty())
|
PP.addMacroDeprecationMsg(II, std::move(MessageString),
|
||||||
PP.addMacroDeprecationMsg(II, std::move(MessageString));
|
Tok.getLocation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2053,6 +2053,47 @@ struct PragmaRestrictExpansionHandler : public PragmaHandler {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// "\#pragma clang final(...)"
|
||||||
|
///
|
||||||
|
/// The syntax is
|
||||||
|
/// \code
|
||||||
|
/// #pragma clang final(MACRO_NAME)
|
||||||
|
/// \endcode
|
||||||
|
struct PragmaFinalHandler : public PragmaHandler {
|
||||||
|
PragmaFinalHandler() : PragmaHandler("final") {}
|
||||||
|
|
||||||
|
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
|
||||||
|
Token &Tok) override {
|
||||||
|
std::string Macro;
|
||||||
|
|
||||||
|
PP.Lex(Tok);
|
||||||
|
if (Tok.isNot(tok::l_paren)) {
|
||||||
|
PP.Diag(Tok, diag::err_expected) << "(";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PP.LexUnexpandedToken(Tok);
|
||||||
|
if (!Tok.is(tok::identifier)) {
|
||||||
|
PP.Diag(Tok, diag::err_expected) << tok::identifier;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||||
|
|
||||||
|
if (!II->hasMacroDefinition()) {
|
||||||
|
PP.Diag(Tok, diag::err_pp_visibility_non_macro) << II;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PP.Lex(Tok);
|
||||||
|
if (Tok.isNot(tok::r_paren)) {
|
||||||
|
PP.Diag(Tok, diag::err_expected) << ")";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
II->setIsFinal(true);
|
||||||
|
PP.addFinalLoc(II, Tok.getLocation());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
/// RegisterBuiltinPragmas - Install the standard preprocessor pragmas:
|
/// RegisterBuiltinPragmas - Install the standard preprocessor pragmas:
|
||||||
|
@ -2084,6 +2125,7 @@ void Preprocessor::RegisterBuiltinPragmas() {
|
||||||
AddPragmaHandler("clang", new PragmaAssumeNonNullHandler());
|
AddPragmaHandler("clang", new PragmaAssumeNonNullHandler());
|
||||||
AddPragmaHandler("clang", new PragmaDeprecatedHandler());
|
AddPragmaHandler("clang", new PragmaDeprecatedHandler());
|
||||||
AddPragmaHandler("clang", new PragmaRestrictExpansionHandler());
|
AddPragmaHandler("clang", new PragmaRestrictExpansionHandler());
|
||||||
|
AddPragmaHandler("clang", new PragmaFinalHandler());
|
||||||
|
|
||||||
// #pragma clang module ...
|
// #pragma clang module ...
|
||||||
auto *ModuleHandler = new PragmaNamespace("module");
|
auto *ModuleHandler = new PragmaNamespace("module");
|
||||||
|
|
|
@ -1409,25 +1409,46 @@ bool Preprocessor::HandleComment(Token &result, SourceRange Comment) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preprocessor::emitMacroDeprecationWarning(const Token &Identifier) {
|
void Preprocessor::emitMacroDeprecationWarning(const Token &Identifier) const {
|
||||||
auto DepMsg = getMacroDeprecationMsg(Identifier.getIdentifierInfo());
|
const MacroAnnotations &A =
|
||||||
if (!DepMsg)
|
getMacroAnnotations(Identifier.getIdentifierInfo());
|
||||||
|
assert(A.DeprecationInfo &&
|
||||||
|
"Macro deprecation warning without recorded annotation!");
|
||||||
|
const MacroAnnotationInfo &Info = *A.DeprecationInfo;
|
||||||
|
if (Info.Message.empty())
|
||||||
Diag(Identifier, diag::warn_pragma_deprecated_macro_use)
|
Diag(Identifier, diag::warn_pragma_deprecated_macro_use)
|
||||||
<< Identifier.getIdentifierInfo() << 0;
|
<< Identifier.getIdentifierInfo() << 0;
|
||||||
else
|
else
|
||||||
Diag(Identifier, diag::warn_pragma_deprecated_macro_use)
|
Diag(Identifier, diag::warn_pragma_deprecated_macro_use)
|
||||||
<< Identifier.getIdentifierInfo() << 1 << *DepMsg;
|
<< Identifier.getIdentifierInfo() << 1 << Info.Message;
|
||||||
|
Diag(Info.Location, diag::note_pp_macro_annotation) << 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preprocessor::emitMacroUnsafeHeaderWarning(const Token &Identifier) {
|
void Preprocessor::emitRestrictExpansionWarning(const Token &Identifier) const {
|
||||||
auto DepMsg = getRestrictExpansionMsg(Identifier.getIdentifierInfo());
|
const MacroAnnotations &A =
|
||||||
if (DepMsg.first.empty())
|
getMacroAnnotations(Identifier.getIdentifierInfo());
|
||||||
|
assert(A.RestrictExpansionInfo &&
|
||||||
|
"Macro restricted expansion warning without recorded annotation!");
|
||||||
|
const MacroAnnotationInfo &Info = *A.RestrictExpansionInfo;
|
||||||
|
if (Info.Message.empty())
|
||||||
Diag(Identifier, diag::warn_pragma_restrict_expansion_macro_use)
|
Diag(Identifier, diag::warn_pragma_restrict_expansion_macro_use)
|
||||||
<< Identifier.getIdentifierInfo() << 0;
|
<< Identifier.getIdentifierInfo() << 0;
|
||||||
else
|
else
|
||||||
Diag(Identifier, diag::warn_pragma_restrict_expansion_macro_use)
|
Diag(Identifier, diag::warn_pragma_restrict_expansion_macro_use)
|
||||||
<< Identifier.getIdentifierInfo() << 1 << DepMsg.first;
|
<< Identifier.getIdentifierInfo() << 1 << Info.Message;
|
||||||
Diag(DepMsg.second, diag::note_pp_macro_annotation) << 1;
|
Diag(Info.Location, diag::note_pp_macro_annotation) << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preprocessor::emitFinalMacroWarning(const Token &Identifier,
|
||||||
|
bool IsUndef) const {
|
||||||
|
const MacroAnnotations &A =
|
||||||
|
getMacroAnnotations(Identifier.getIdentifierInfo());
|
||||||
|
assert(A.FinalAnnotationLoc &&
|
||||||
|
"Final macro warning without recorded annotation!");
|
||||||
|
|
||||||
|
Diag(Identifier, diag::warn_pragma_final_macro)
|
||||||
|
<< Identifier.getIdentifierInfo() << (IsUndef ? 0 : 1);
|
||||||
|
Diag(*A.FinalAnnotationLoc, diag::note_pp_macro_annotation) << 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleLoader::~ModuleLoader() = default;
|
ModuleLoader::~ModuleLoader() = default;
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
// expected-warning@+2{{macro 'Foo' has been marked as deprecated}}
|
||||||
|
// expected-warning@+1{{macro 'Foo' has been marked as unsafe for use in headers}}
|
||||||
|
#if Foo
|
||||||
|
#endif
|
|
@ -4,7 +4,7 @@
|
||||||
// expected-error@+1{{expected identifier}}
|
// expected-error@+1{{expected identifier}}
|
||||||
#pragma clang restrict_expansion(4
|
#pragma clang restrict_expansion(4
|
||||||
|
|
||||||
// expected-error@+1{{no macro named foo}}
|
// expected-error@+1{{no macro named 'foo'}}
|
||||||
#pragma clang restrict_expansion(foo)
|
#pragma clang restrict_expansion(foo)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,11 @@
|
||||||
// expected-error@+1{{expected identifier}}
|
// expected-error@+1{{expected identifier}}
|
||||||
#pragma clang deprecated(4
|
#pragma clang deprecated(4
|
||||||
|
|
||||||
// expected-error@+1{{no macro named foo}}
|
// expected-error@+1{{no macro named 'foo'}}
|
||||||
#pragma clang deprecated(foo)
|
#pragma clang deprecated(foo)
|
||||||
|
|
||||||
#define bar 1
|
#define bar 1
|
||||||
|
// expected-note@+1{{macro marked 'deprecated' here}}
|
||||||
#pragma clang deprecated(bar, "bar is deprecated use 1")
|
#pragma clang deprecated(bar, "bar is deprecated use 1")
|
||||||
|
|
||||||
// expected-warning@+1{{macro 'bar' has been marked as deprecated: bar is deprecated use 1}}
|
// expected-warning@+1{{macro 'bar' has been marked as deprecated: bar is deprecated use 1}}
|
||||||
|
@ -17,6 +18,14 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define foo 1
|
#define foo 1
|
||||||
|
// expected-note@+8{{macro marked 'deprecated' here}}
|
||||||
|
// expected-note@+7{{macro marked 'deprecated' here}}
|
||||||
|
// expected-note@+6{{macro marked 'deprecated' here}}
|
||||||
|
// expected-note@+5{{macro marked 'deprecated' here}}
|
||||||
|
// expected-note@+4{{macro marked 'deprecated' here}}
|
||||||
|
// expected-note@+3{{macro marked 'deprecated' here}}
|
||||||
|
// expected-note@+2{{macro marked 'deprecated' here}}
|
||||||
|
// expected-note@+1{{macro marked 'deprecated' here}}
|
||||||
#pragma clang deprecated(foo)
|
#pragma clang deprecated(foo)
|
||||||
|
|
||||||
// expected-error@+1{{expected )}}
|
// expected-error@+1{{expected )}}
|
||||||
|
@ -39,7 +48,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
// expected-error@+1{{no macro named main}}
|
// expected-error@+1{{no macro named 'main'}}
|
||||||
#pragma clang deprecated(main)
|
#pragma clang deprecated(main)
|
||||||
|
|
||||||
// expected-warning@+1{{macro 'foo' has been marked as deprecated}}
|
// expected-warning@+1{{macro 'foo' has been marked as deprecated}}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
// RUN: %clang_cc1 -Wfinal-macro %s -fsyntax-only -verify
|
||||||
|
|
||||||
|
// Test warning production
|
||||||
|
#define Foo 1
|
||||||
|
// expected-note@+1 4{{macro marked 'final' here}}
|
||||||
|
#pragma clang final(Foo)
|
||||||
|
|
||||||
|
// expected-warning@+2{{macro 'Foo' has been marked as final and should not be redefined}}
|
||||||
|
// expected-note@+1{{previous definition is here}}
|
||||||
|
#define Foo 1
|
||||||
|
|
||||||
|
// expected-warning@+2{{macro 'Foo' has been marked as final and should not be redefined}}
|
||||||
|
// expected-warning@+1{{'Foo' macro redefined}}
|
||||||
|
#define Foo 2
|
||||||
|
|
||||||
|
// expected-warning@+1{{redefining builtin macro}}
|
||||||
|
#define __TIME__ 1
|
||||||
|
|
||||||
|
// expected-warning@+1{{undefining builtin macro}}
|
||||||
|
#undef __TIMESTAMP__
|
||||||
|
|
||||||
|
// expected-warning@+1{{macro 'Foo' has been marked as final and should not be undefined}}
|
||||||
|
#undef Foo
|
||||||
|
// expected-warning@+1{{macro 'Foo' has been marked as final and should not be redefined}}
|
||||||
|
#define Foo 3
|
||||||
|
|
||||||
|
// Test parse errors
|
||||||
|
// expected-error@+1{{expected (}}
|
||||||
|
#pragma clang final
|
||||||
|
|
||||||
|
// expected-error@+1{{expected )}}
|
||||||
|
#pragma clang final(Foo
|
||||||
|
|
||||||
|
// expected-error@+1{{no macro named 'Baz'}}
|
||||||
|
#pragma clang final(Baz)
|
||||||
|
|
||||||
|
// expected-error@+1{{expected identifier}}
|
||||||
|
#pragma clang final(4)
|
||||||
|
|
||||||
|
// expected-error@+1{{expected (}}
|
||||||
|
#pragma clang final Baz
|
||||||
|
|
||||||
|
// no diagnostics triggered by these pragmas.
|
||||||
|
#pragma clang deprecated(Foo)
|
||||||
|
#pragma clang restrict_expansion(Foo)
|
|
@ -11,4 +11,17 @@
|
||||||
// not-expected-warning@+1{{macro 'UNSAFE_MACRO_2' has been marked as deprecated: Don't use this!}}
|
// not-expected-warning@+1{{macro 'UNSAFE_MACRO_2' has been marked as deprecated: Don't use this!}}
|
||||||
#pragma clang restrict_expansion(UNSAFE_MACRO_2, "Don't use this!")
|
#pragma clang restrict_expansion(UNSAFE_MACRO_2, "Don't use this!")
|
||||||
|
|
||||||
// expected-no-diagnostics
|
|
||||||
|
#define Foo 1
|
||||||
|
#pragma clang final(Foo)
|
||||||
|
// expected-note@+2{{macro marked 'deprecated' here}}
|
||||||
|
// expected-note@+1{{macro marked 'deprecated' here}}
|
||||||
|
#pragma clang deprecated(Foo)
|
||||||
|
// expected-note@+1{{macro marked 'restrict_expansion' here}}
|
||||||
|
#pragma clang restrict_expansion(Foo)
|
||||||
|
|
||||||
|
// Test that unsafe_header and deprecated markings stick around after the undef
|
||||||
|
#include "Inputs/final-macro.h"
|
||||||
|
|
||||||
|
// expected-warning@+1{{macro 'Foo' has been marked as deprecated}}
|
||||||
|
const int X = Foo;
|
||||||
|
|
Loading…
Reference in New Issue