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 /// Store declaration pairs already found to be non-equivalent. 43 /// key: (from, to, IgnoreTemplateParmDepth) 44 using NonEquivalentDeclSet = llvm::DenseSet<std::tuple<Decl *, Decl *, int>>; 45 46 /// The language options to use for making a structural equivalence check. 47 const LangOptions &LangOpts; 48 49 /// AST contexts for which we are checking structural equivalence. 50 ASTContext &FromCtx, &ToCtx; 51 52 // Queue of from-to Decl pairs that are to be checked to determine the final 53 // result of equivalence of a starting Decl pair. 54 std::queue<std::pair<Decl *, Decl *>> DeclsToCheck; 55 56 // Set of from-to Decl pairs that are already visited during the check 57 // (are in or were once in \c DeclsToCheck) of a starting Decl pair. 58 llvm::DenseSet<std::pair<Decl *, Decl *>> VisitedDecls; 59 60 /// Declaration (from, to) pairs that are known not to be equivalent 61 /// (which we have already complained about). 62 NonEquivalentDeclSet &NonEquivalentDecls; 63 64 StructuralEquivalenceKind EqKind; 65 66 /// Whether we're being strict about the spelling of types when 67 /// unifying two types. 68 bool StrictTypeSpelling; 69 70 /// Whether warn or error on tag type mismatches. 71 bool ErrorOnTagTypeMismatch; 72 73 /// Whether to complain about failures. 74 bool Complain; 75 76 /// \c true if the last diagnostic came from ToCtx. 77 bool LastDiagFromC2 = false; 78 79 /// Whether to ignore comparing the depth of template param(TemplateTypeParm) 80 bool IgnoreTemplateParmDepth; 81 82 StructuralEquivalenceContext(const LangOptions &LangOpts, ASTContext &FromCtx, 83 ASTContext &ToCtx, 84 NonEquivalentDeclSet &NonEquivalentDecls, 85 StructuralEquivalenceKind EqKind, 86 bool StrictTypeSpelling = false, 87 bool Complain = true, 88 bool ErrorOnTagTypeMismatch = false, 89 bool IgnoreTemplateParmDepth = false) LangOptsStructuralEquivalenceContext90 : LangOpts(LangOpts), FromCtx(FromCtx), ToCtx(ToCtx), 91 NonEquivalentDecls(NonEquivalentDecls), EqKind(EqKind), 92 StrictTypeSpelling(StrictTypeSpelling), 93 ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain), 94 IgnoreTemplateParmDepth(IgnoreTemplateParmDepth) {} 95 96 DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID); 97 DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID); 98 99 /// Determine whether the two declarations are structurally 100 /// 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(Decl *D1, Decl *D2); 106 107 /// Determine whether the two types are structurally equivalent. 108 /// Implementation functions (all static functions in 109 /// ASTStructuralEquivalence.cpp) must never call this function because that 110 /// will wreak havoc the internal state (\c DeclsToCheck and 111 /// \c VisitedDecls members) and can cause faulty equivalent results. 112 bool IsEquivalent(QualType T1, QualType T2); 113 114 /// Determine whether the two statements are structurally equivalent. 115 /// Implementation functions (all static functions in 116 /// ASTStructuralEquivalence.cpp) must never call this function because that 117 /// will wreak havoc the internal state (\c DeclsToCheck and 118 /// \c VisitedDecls members) and can cause faulty equivalent results. 119 bool IsEquivalent(Stmt *S1, Stmt *S2); 120 121 /// Find the index of the given anonymous struct/union within its 122 /// context. 123 /// 124 /// \returns Returns the index of this anonymous struct/union in its context, 125 /// including the next assigned index (if none of them match). Returns an 126 /// empty option if the context is not a record, i.e.. if the anonymous 127 /// struct/union is at namespace or block scope. 128 /// 129 /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It 130 /// probably makes more sense in some other common place then here. 131 static UnsignedOrNone findUntaggedStructOrUnionIndex(RecordDecl *Anon); 132 133 // If ErrorOnTagTypeMismatch is set, return the error, otherwise get the 134 // relevant warning for the input error diagnostic. 135 unsigned getApplicableDiagnostic(unsigned ErrorDiagnostic); 136 137 private: 138 /// Finish checking all of the structural equivalences. 139 /// 140 /// \returns true if the equivalence check failed (non-equivalence detected), 141 /// false if equivalence was detected. 142 bool Finish(); 143 144 /// Check for common properties at Finish. 145 /// \returns true if D1 and D2 may be equivalent, 146 /// false if they are for sure not. 147 bool CheckCommonEquivalence(Decl *D1, Decl *D2); 148 149 /// Check for class dependent properties at Finish. 150 /// \returns true if D1 and D2 may be equivalent, 151 /// false if they are for sure not. 152 bool CheckKindSpecificEquivalence(Decl *D1, Decl *D2); 153 }; 154 155 } // namespace clang 156 157 #endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H 158