1//===- ASTStructuralEquivalence.h -------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the StructuralEquivalenceContext class which checks for
10// structural equivalence between types.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
15#define LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
16
17#include "clang/AST/DeclBase.h"
18#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/DenseSet.h"
20#include <optional>
21#include <queue>
22#include <utility>
23
24namespace clang {
25
26class ASTContext;
27class Decl;
28class DiagnosticBuilder;
29class QualType;
30class RecordDecl;
31class SourceLocation;
32
33/// \brief Whether to perform a normal or minimal equivalence check.
34/// In case of `Minimal`, we do not perform a recursive check of decls with
35/// external storage.
36enum class StructuralEquivalenceKind {
37 Default,
38 Minimal,
39};
40
41struct StructuralEquivalenceContext {
42 /// AST contexts for which we are checking structural equivalence.
43 ASTContext &FromCtx, &ToCtx;
44
45 // Queue of from-to Decl pairs that are to be checked to determine the final
46 // result of equivalence of a starting Decl pair.
47 std::queue<std::pair<Decl *, Decl *>> DeclsToCheck;
48
49 // Set of from-to Decl pairs that are already visited during the check
50 // (are in or were once in \c DeclsToCheck) of a starting Decl pair.
51 llvm::DenseSet<std::pair<Decl *, Decl *>> VisitedDecls;
52
53 /// Declaration (from, to) pairs that are known not to be equivalent
54 /// (which we have already complained about).
55 llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls;
56
57 StructuralEquivalenceKind EqKind;
58
59 /// Whether we're being strict about the spelling of types when
60 /// unifying two types.
61 bool StrictTypeSpelling;
62
63 /// Whether warn or error on tag type mismatches.
64 bool ErrorOnTagTypeMismatch;
65
66 /// Whether to complain about failures.
67 bool Complain;
68
69 /// \c true if the last diagnostic came from ToCtx.
70 bool LastDiagFromC2 = false;
71
72 /// Whether to ignore comparing the depth of template param(TemplateTypeParm)
73 bool IgnoreTemplateParmDepth;
74
75 StructuralEquivalenceContext(
76 ASTContext &FromCtx, ASTContext &ToCtx,
77 llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls,
78 StructuralEquivalenceKind EqKind, bool StrictTypeSpelling = false,
79 bool Complain = true, bool ErrorOnTagTypeMismatch = false,
80 bool IgnoreTemplateParmDepth = false)
81 : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls),
82 EqKind(EqKind), StrictTypeSpelling(StrictTypeSpelling),
83 ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain),
84 IgnoreTemplateParmDepth(IgnoreTemplateParmDepth) {}
85
86 DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID);
87 DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID);
88
89 /// Determine whether the two declarations are structurally
90 /// equivalent.
91 /// Implementation functions (all static functions in
92 /// ASTStructuralEquivalence.cpp) must never call this function because that
93 /// will wreak havoc the internal state (\c DeclsToCheck and
94 /// \c VisitedDecls members) and can cause faulty equivalent results.
95 bool IsEquivalent(Decl *D1, Decl *D2);
96
97 /// Determine whether the two types are structurally equivalent.
98 /// Implementation functions (all static functions in
99 /// ASTStructuralEquivalence.cpp) must never call this function because that
100 /// will wreak havoc the internal state (\c DeclsToCheck and
101 /// \c VisitedDecls members) and can cause faulty equivalent results.
102 bool IsEquivalent(QualType T1, QualType T2);
103
104 /// Determine whether the two statements are structurally equivalent.
105 /// Implementation functions (all static functions in
106 /// ASTStructuralEquivalence.cpp) must never call this function because that
107 /// will wreak havoc the internal state (\c DeclsToCheck and
108 /// \c VisitedDecls members) and can cause faulty equivalent results.
109 bool IsEquivalent(Stmt *S1, Stmt *S2);
110
111 /// Find the index of the given anonymous struct/union within its
112 /// context.
113 ///
114 /// \returns Returns the index of this anonymous struct/union in its context,
115 /// including the next assigned index (if none of them match). Returns an
116 /// empty option if the context is not a record, i.e.. if the anonymous
117 /// struct/union is at namespace or block scope.
118 ///
119 /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It
120 /// probably makes more sense in some other common place then here.
121 static std::optional<unsigned>
122 findUntaggedStructOrUnionIndex(RecordDecl *Anon);
123
124 // If ErrorOnTagTypeMismatch is set, return the error, otherwise get the
125 // relevant warning for the input error diagnostic.
126 unsigned getApplicableDiagnostic(unsigned ErrorDiagnostic);
127
128private:
129 /// Finish checking all of the structural equivalences.
130 ///
131 /// \returns true if the equivalence check failed (non-equivalence detected),
132 /// false if equivalence was detected.
133 bool Finish();
134
135 /// Check for common properties at Finish.
136 /// \returns true if D1 and D2 may be equivalent,
137 /// false if they are for sure not.
138 bool CheckCommonEquivalence(Decl *D1, Decl *D2);
139
140 /// Check for class dependent properties at Finish.
141 /// \returns true if D1 and D2 may be equivalent,
142 /// false if they are for sure not.
143 bool CheckKindSpecificEquivalence(Decl *D1, Decl *D2);
144};
145
146} // namespace clang
147
148#endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
149

source code of clang/include/clang/AST/ASTStructuralEquivalence.h