Skip to content

[Clang] [NFC] Introduce a helper for emitting compatibility diagnostics #132348

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions clang/include/clang/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ macro(clang_diag_gen component)
-gen-clang-diags-enums -clang-component=${component}
SOURCE Diagnostic.td
TARGET ClangDiagnostic${component}Enums)

clang_tablegen(Diagnostic${component}CompatIDs.inc
-gen-clang-diags-compat-ids -clang-component=${component}
SOURCE Diagnostic.td
TARGET ClangDiagnostic${component}CompatIDs)
endmacro(clang_diag_gen)

clang_diag_gen(Analysis)
Expand All @@ -31,6 +36,11 @@ clang_tablegen(DiagnosticIndexName.inc -gen-clang-diags-index-name
SOURCE Diagnostic.td
TARGET ClangDiagnosticIndexName)

clang_tablegen(DiagnosticAllCompatIDs.inc
-gen-clang-diags-compat-ids
SOURCE Diagnostic.td
TARGET ClangDiagnosticAllCompatIDs)

clang_tablegen(AttrList.inc -gen-clang-attr-list
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE Attr.td
Expand Down
18 changes: 18 additions & 0 deletions clang/include/clang/Basic/Diagnostic.td
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,19 @@ class DefaultWarnNoWerror {
}
class DefaultRemark { Severity DefaultSeverity = SEV_Remark; }

class CompatWarningId<string name, int std, string diag, string diag_pre> {
string Component = ?;
string Name = name;
string Diag = diag;
string DiagPre = diag_pre;
int Std = std;

// This is unused, but Tablegen will complain if it's missing because we define
// the compatibility ids in the same place as the other diagnostics (which means
// that we'll be inside a 'let CategoryName = "" in { ... }' block).
string CategoryName = ?;
}

// C++ compatibility warnings.
multiclass CXXCompat<
string message,
Expand All @@ -178,6 +191,11 @@ multiclass CXXCompat<
"CXX98Compat",
"CXXPre"#std_ver#"Compat"))>,
DefaultIgnore;

def : CompatWarningId<
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have another layer of abstraction here for C vs C++ vs whatever other language compat warnings?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m still figuring out how to integrate the C compatibility warnings; for now this is just for C++, but I think we can definitely extend this later

NAME, std_ver,
"compat_cxx"#std_ver#"_"#NAME,
"compat_pre_cxx"#std_ver#"_"#NAME>;
}

// These generate pairs of C++ compatibility warnings of the form:
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticAST.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ enum {
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM
} // end namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticASTCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // end namespace clang

#endif // LLVM_CLANG_BASIC_DIAGNOSTICAST_H
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ enum {
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM
} // end namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticAnalysisCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // end namespace clang

#endif // LLVM_CLANG_BASIC_DIAGNOSTICANALYSIS_H
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticComment.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ enum {
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM
} // end namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticCommentCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // end namespace clang

#endif // LLVM_CLANG_BASIC_DIAGNOSTICCOMMENT_H
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticCrossTU.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ enum {
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM
} // end namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticCrossTUCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // end namespace clang

#endif // LLVM_CLANG_BASIC_DIAGNOSTICCROSSTU_H
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ enum {
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM
} // end namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticDriverCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // end namespace clang

#endif // LLVM_CLANG_BASIC_DIAGNOSTICDRIVER_H
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticFrontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ enum {
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM
} // end namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticFrontendCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // end namespace clang

#endif // LLVM_CLANG_BASIC_DIAGNOSTICFRONTEND_H
18 changes: 18 additions & 0 deletions clang/include/clang/Basic/DiagnosticIDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
namespace clang {
class DiagnosticsEngine;
class DiagnosticBuilder;
class LangOptions;
class SourceLocation;

// Import the diagnostic enums themselves.
Expand Down Expand Up @@ -104,6 +105,18 @@ namespace clang {
};
}

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticCommonCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat

class DiagnosticMapping {
LLVM_PREFERRED_TYPE(diag::Severity)
unsigned Severity : 3;
Expand Down Expand Up @@ -464,6 +477,11 @@ class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
/// given group name.
static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group);

/// Get the appropriate diagnostic Id to use for issuing a compatibility
/// diagnostic. For use by the various DiagCompat() helpers.
static unsigned getCXXCompatDiagId(const LangOptions &LangOpts,
unsigned CompatDiagId);

private:
/// Classify the specified diagnostic ID into a Level, consumable by
/// the DiagnosticClient.
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticInstallAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,17 @@ enum {
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM
} // namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticInstallAPICompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // namespace clang
#endif // LLVM_CLANG_BASIC_DIAGNOSTICINSTALLAPI_H
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticLex.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ enum {
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM
} // end namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticLexCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // end namespace clang

#endif // LLVM_CLANG_BASIC_DIAGNOSTICLEX_H
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticParse.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ enum {
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM
} // end namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticParseCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // end namespace clang

#endif // LLVM_CLANG_BASIC_DIAGNOSTICPARSE_H
12 changes: 6 additions & 6 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
//===----------------------------------------------------------------------===//

let Component = "Parse" in {
let CategoryName = "Parse Issue" in {
// C++11 compatibility with C++98.
defm enum_fixed_underlying_type : CXX11Compat<
"enumeration types with a fixed underlying type are",
/*ext_warn=*/false>;
}

def err_asm_qualifier_ignored : Error<
"expected 'volatile', 'inline', 'goto', or '('">, CatInlineAsm;
Expand Down Expand Up @@ -107,9 +113,6 @@ def err_enumerator_list_missing_comma : Error<
"missing ',' between enumerators">;
def err_enumerator_unnamed_no_def : Error<
"unnamed enumeration must be a definition">;
def ext_cxx11_enum_fixed_underlying_type : Extension<
"enumeration types with a fixed underlying type are a C++11 extension">,
InGroup<CXX11>;
def ext_ms_c_enum_fixed_underlying_type : Extension<
"enumeration types with a fixed underlying type are a Microsoft extension">,
InGroup<MicrosoftFixedEnum>;
Expand All @@ -119,9 +122,6 @@ def ext_c23_enum_fixed_underlying_type : Extension<
def warn_c17_compat_enum_fixed_underlying_type : Warning<
"enumeration types with a fixed underlying type are incompatible with C standards before C23">,
DefaultIgnore, InGroup<CPre23Compat>;
def warn_cxx98_compat_enum_fixed_underlying_type : Warning<
"enumeration types with a fixed underlying type are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def ext_enum_base_in_type_specifier : ExtWarn<
"non-defining declaration of enumeration with a fixed underlying type is "
"only permitted as a standalone declaration"
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticRefactoring.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ enum {
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM
} // end namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticRefactoringCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // end namespace clang

#endif // LLVM_CLANG_BASIC_DIAGNOSTICREFACTORING_H
13 changes: 13 additions & 0 deletions clang/include/clang/Basic/DiagnosticSema.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,20 @@ enum {
#undef DIAG_ENUM_END
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM

} // end namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticSemaCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // end namespace clang

#endif // LLVM_CLANG_BASIC_DIAGNOSTICSEMA_H
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ defm decomp_decl_cond : CXX26Compat<"structured binding declaration in a conditi

// Compatibility warnings duplicated across multiple language versions.
foreach std = [14, 20, 23] in {
defm constexpr_body_invalid_stmt : CXXCompat<
defm cxx#std#_constexpr_body_invalid_stmt : CXXCompat<
"use of this statement in a constexpr %select{function|constructor}0 is", std>;
}

Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticSerialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ enum {
#undef DIAG_ENUM_ITEM
#undef DIAG_ENUM
} // end namespace diag

namespace diag_compat {
#define DIAG_COMPAT_IDS_BEGIN() enum {
#define DIAG_COMPAT_IDS_END() \
} \
;
#define DIAG_COMPAT_ID(IDX, NAME, ...) NAME = IDX,
#include "clang/Basic/DiagnosticSerializationCompatIDs.inc"
#undef DIAG_COMPAT_ID
#undef DIAG_COMPAT_IDS_BEGIN
#undef DIAG_COMPAT_IDS_END
} // end namespace diag_compat
} // end namespace clang

#endif // LLVM_CLANG_BASIC_DIAGNOSTICSERIALIZATION_H
6 changes: 6 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,12 @@ class Parser : public CodeCompletionHandler {
return Diag(Tok, DiagID);
}

DiagnosticBuilder DiagCompat(SourceLocation Loc, unsigned CompatDiagId);
DiagnosticBuilder DiagCompat(const Token &Tok, unsigned CompatDiagId);
DiagnosticBuilder DiagCompat(unsigned CompatDiagId) {
return DiagCompat(Tok, CompatDiagId);
}

private:
void SuggestParentheses(SourceLocation Loc, unsigned DK,
SourceRange ParenRange);
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Sema/SemaBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ class SemaBase {
SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD,
bool DeferHint = false);

/// Emit a compatibility diagnostic.
SemaDiagnosticBuilder DiagCompat(SourceLocation Loc, unsigned CompatDiagId,
bool DeferHint = false);

/// Build a partial diagnostic.
PartialDiagnostic PDiag(unsigned DiagID = 0);
};
Expand Down
Loading