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 24 namespace clang { 25 26 class ASTContext; 27 class Decl; 28 class DiagnosticBuilder; 29 class QualType; 30 class RecordDecl; 31 class 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. 36 enum class StructuralEquivalenceKind { 37 Default, 38 Minimal, 39 }; 40 41 struct 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 128 private: 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