Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:29

0001 //===- ASTStructuralEquivalence.h -------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file defines the StructuralEquivalenceContext class which checks for
0010 //  structural equivalence between types.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
0015 #define LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
0016 
0017 #include "clang/AST/DeclBase.h"
0018 #include "llvm/ADT/DenseMap.h"
0019 #include "llvm/ADT/DenseSet.h"
0020 #include <optional>
0021 #include <queue>
0022 #include <utility>
0023 
0024 namespace clang {
0025 
0026 class ASTContext;
0027 class Decl;
0028 class DiagnosticBuilder;
0029 class QualType;
0030 class RecordDecl;
0031 class SourceLocation;
0032 
0033 /// \brief Whether to perform a normal or minimal equivalence check.
0034 /// In case of `Minimal`, we do not perform a recursive check of decls with
0035 /// external storage.
0036 enum class StructuralEquivalenceKind {
0037   Default,
0038   Minimal,
0039 };
0040 
0041 struct StructuralEquivalenceContext {
0042   /// Store declaration pairs already found to be non-equivalent.
0043   /// key: (from, to, IgnoreTemplateParmDepth)
0044   using NonEquivalentDeclSet = llvm::DenseSet<std::tuple<Decl *, Decl *, int>>;
0045 
0046   /// AST contexts for which we are checking structural equivalence.
0047   ASTContext &FromCtx, &ToCtx;
0048 
0049   // Queue of from-to Decl pairs that are to be checked to determine the final
0050   // result of equivalence of a starting Decl pair.
0051   std::queue<std::pair<Decl *, Decl *>> DeclsToCheck;
0052 
0053   // Set of from-to Decl pairs that are already visited during the check
0054   // (are in or were once in \c DeclsToCheck) of a starting Decl pair.
0055   llvm::DenseSet<std::pair<Decl *, Decl *>> VisitedDecls;
0056 
0057   /// Declaration (from, to) pairs that are known not to be equivalent
0058   /// (which we have already complained about).
0059   NonEquivalentDeclSet &NonEquivalentDecls;
0060 
0061   StructuralEquivalenceKind EqKind;
0062 
0063   /// Whether we're being strict about the spelling of types when
0064   /// unifying two types.
0065   bool StrictTypeSpelling;
0066 
0067   /// Whether warn or error on tag type mismatches.
0068   bool ErrorOnTagTypeMismatch;
0069 
0070   /// Whether to complain about failures.
0071   bool Complain;
0072 
0073   /// \c true if the last diagnostic came from ToCtx.
0074   bool LastDiagFromC2 = false;
0075 
0076   /// Whether to ignore comparing the depth of template param(TemplateTypeParm)
0077   bool IgnoreTemplateParmDepth;
0078 
0079   StructuralEquivalenceContext(ASTContext &FromCtx, ASTContext &ToCtx,
0080                                NonEquivalentDeclSet &NonEquivalentDecls,
0081                                StructuralEquivalenceKind EqKind,
0082                                bool StrictTypeSpelling = false,
0083                                bool Complain = true,
0084                                bool ErrorOnTagTypeMismatch = false,
0085                                bool IgnoreTemplateParmDepth = false)
0086       : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls),
0087         EqKind(EqKind), StrictTypeSpelling(StrictTypeSpelling),
0088         ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain),
0089         IgnoreTemplateParmDepth(IgnoreTemplateParmDepth) {}
0090 
0091   DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID);
0092   DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID);
0093 
0094   /// Determine whether the two declarations are structurally
0095   /// equivalent.
0096   /// Implementation functions (all static functions in
0097   /// ASTStructuralEquivalence.cpp) must never call this function because that
0098   /// will wreak havoc the internal state (\c DeclsToCheck and
0099   /// \c VisitedDecls members) and can cause faulty equivalent results.
0100   bool IsEquivalent(Decl *D1, Decl *D2);
0101 
0102   /// Determine whether the two types are structurally equivalent.
0103   /// Implementation functions (all static functions in
0104   /// ASTStructuralEquivalence.cpp) must never call this function because that
0105   /// will wreak havoc the internal state (\c DeclsToCheck and
0106   /// \c VisitedDecls members) and can cause faulty equivalent results.
0107   bool IsEquivalent(QualType T1, QualType T2);
0108 
0109   /// Determine whether the two statements are structurally equivalent.
0110   /// Implementation functions (all static functions in
0111   /// ASTStructuralEquivalence.cpp) must never call this function because that
0112   /// will wreak havoc the internal state (\c DeclsToCheck and
0113   /// \c VisitedDecls members) and can cause faulty equivalent results.
0114   bool IsEquivalent(Stmt *S1, Stmt *S2);
0115 
0116   /// Find the index of the given anonymous struct/union within its
0117   /// context.
0118   ///
0119   /// \returns Returns the index of this anonymous struct/union in its context,
0120   /// including the next assigned index (if none of them match). Returns an
0121   /// empty option if the context is not a record, i.e.. if the anonymous
0122   /// struct/union is at namespace or block scope.
0123   ///
0124   /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It
0125   /// probably makes more sense in some other common place then here.
0126   static std::optional<unsigned>
0127   findUntaggedStructOrUnionIndex(RecordDecl *Anon);
0128 
0129   // If ErrorOnTagTypeMismatch is set, return the error, otherwise get the
0130   // relevant warning for the input error diagnostic.
0131   unsigned getApplicableDiagnostic(unsigned ErrorDiagnostic);
0132 
0133 private:
0134   /// Finish checking all of the structural equivalences.
0135   ///
0136   /// \returns true if the equivalence check failed (non-equivalence detected),
0137   /// false if equivalence was detected.
0138   bool Finish();
0139 
0140   /// Check for common properties at Finish.
0141   /// \returns true if D1 and D2 may be equivalent,
0142   /// false if they are for sure not.
0143   bool CheckCommonEquivalence(Decl *D1, Decl *D2);
0144 
0145   /// Check for class dependent properties at Finish.
0146   /// \returns true if D1 and D2 may be equivalent,
0147   /// false if they are for sure not.
0148   bool CheckKindSpecificEquivalence(Decl *D1, Decl *D2);
0149 };
0150 
0151 } // namespace clang
0152 
0153 #endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H