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 "llvm/ADT/Optional.h" 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 StructuralEquivalenceContext( 73 ASTContext &FromCtx, ASTContext &ToCtx, 74 llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls, 75 StructuralEquivalenceKind EqKind, 76 bool StrictTypeSpelling = false, bool Complain = true, 77 bool ErrorOnTagTypeMismatch = false) FromCtxStructuralEquivalenceContext78 : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls), 79 EqKind(EqKind), StrictTypeSpelling(StrictTypeSpelling), 80 ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain) {} 81 82 DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID); 83 DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID); 84 85 /// Determine whether the two declarations are structurally 86 /// equivalent. 87 /// Implementation functions (all static functions in 88 /// ASTStructuralEquivalence.cpp) must never call this function because that 89 /// will wreak havoc the internal state (\c DeclsToCheck and 90 /// \c VisitedDecls members) and can cause faulty equivalent results. 91 bool IsEquivalent(Decl *D1, Decl *D2); 92 93 /// Determine whether the two types are structurally equivalent. 94 /// Implementation functions (all static functions in 95 /// ASTStructuralEquivalence.cpp) must never call this function because that 96 /// will wreak havoc the internal state (\c DeclsToCheck and 97 /// \c VisitedDecls members) and can cause faulty equivalent results. 98 bool IsEquivalent(QualType T1, QualType T2); 99 100 /// Determine whether the two statements are structurally equivalent. 101 /// Implementation functions (all static functions in 102 /// ASTStructuralEquivalence.cpp) must never call this function because that 103 /// will wreak havoc the internal state (\c DeclsToCheck and 104 /// \c VisitedDecls members) and can cause faulty equivalent results. 105 bool IsEquivalent(Stmt *S1, Stmt *S2); 106 107 /// Find the index of the given anonymous struct/union within its 108 /// context. 109 /// 110 /// \returns Returns the index of this anonymous struct/union in its context, 111 /// including the next assigned index (if none of them match). Returns an 112 /// empty option if the context is not a record, i.e.. if the anonymous 113 /// struct/union is at namespace or block scope. 114 /// 115 /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It 116 /// probably makes more sense in some other common place then here. 117 static llvm::Optional<unsigned> 118 findUntaggedStructOrUnionIndex(RecordDecl *Anon); 119 120 // If ErrorOnTagTypeMismatch is set, return the the error, otherwise get the 121 // relevant warning for the input error diagnostic. 122 unsigned getApplicableDiagnostic(unsigned ErrorDiagnostic); 123 124 private: 125 /// Finish checking all of the structural equivalences. 126 /// 127 /// \returns true if the equivalence check failed (non-equivalence detected), 128 /// false if equivalence was detected. 129 bool Finish(); 130 131 /// Check for common properties at Finish. 132 /// \returns true if D1 and D2 may be equivalent, 133 /// false if they are for sure not. 134 bool CheckCommonEquivalence(Decl *D1, Decl *D2); 135 136 /// Check for class dependent properties at Finish. 137 /// \returns true if D1 and D2 may be equivalent, 138 /// false if they are for sure not. 139 bool CheckKindSpecificEquivalence(Decl *D1, Decl *D2); 140 }; 141 142 } // namespace clang 143 144 #endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H 145