10
10
//
11
11
// ===----------------------------------------------------------------------===//
12
12
13
- #include " clang/Sema/SemaInternal.h"
14
13
#include " clang/AST/ASTMutationListener.h"
15
14
#include " clang/AST/CXXInheritance.h"
16
15
#include " clang/AST/Expr.h"
19
18
#include " clang/AST/TypeLoc.h"
20
19
#include " clang/Basic/Diagnostic.h"
21
20
#include " clang/Basic/SourceManager.h"
21
+ #include " clang/Sema/EnterExpressionEvaluationContext.h"
22
+ #include " clang/Sema/SemaInternal.h"
23
+ #include " clang/Sema/Template.h"
22
24
#include " llvm/ADT/SmallPtrSet.h"
23
25
#include " llvm/ADT/SmallString.h"
24
26
#include < optional>
@@ -314,6 +316,22 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
314
316
return false ;
315
317
}
316
318
319
+ if (Old->getExceptionSpecType () == EST_DependentNoexcept &&
320
+ New->getExceptionSpecType () == EST_DependentNoexcept) {
321
+ const auto *OldType = Old->getType ()->getAs <FunctionProtoType>();
322
+ const auto *NewType = New->getType ()->getAs <FunctionProtoType>();
323
+ OldType = ResolveExceptionSpec (New->getLocation (), OldType);
324
+ if (!OldType)
325
+ return false ;
326
+ NewType = ResolveExceptionSpec (New->getLocation (), NewType);
327
+ if (!NewType)
328
+ return false ;
329
+
330
+ if (AreExceptionSpecsEqual (Old, OldType->getNoexceptExpr (), New,
331
+ NewType->getNoexceptExpr ()))
332
+ return false ;
333
+ }
334
+
317
335
// Check the types as written: they must match before any exception
318
336
// specification adjustment is applied.
319
337
if (!CheckEquivalentExceptionSpecImpl (
@@ -501,6 +519,89 @@ bool Sema::CheckEquivalentExceptionSpec(
501
519
return Result;
502
520
}
503
521
522
+ static const Expr *SubstituteExceptionSpecWithoutEvaluation (
523
+ Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo,
524
+ const Expr *ExceptionSpec) {
525
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs (
526
+ DeclInfo.getDecl (), DeclInfo.getLexicalDeclContext (),
527
+ /* Final=*/ false , /* Innermost=*/ std::nullopt,
528
+ /* RelativeToPrimary=*/ true , /* ForConstraintInstantiation=*/ true );
529
+
530
+ if (!MLTAL.getNumSubstitutedLevels ())
531
+ return ExceptionSpec;
532
+
533
+ Sema::SFINAETrap SFINAE (S, /* AccessCheckingSFINAE=*/ false );
534
+
535
+ Sema::InstantiatingTemplate Inst (
536
+ S, DeclInfo.getLocation (),
537
+ const_cast <FunctionDecl *>(DeclInfo.getDecl ()->getAsFunction ()),
538
+ Sema::InstantiatingTemplate::ExceptionSpecification ());
539
+ if (Inst.isInvalid ())
540
+ return nullptr ;
541
+
542
+ // Set up a dummy 'instantiation' scope in the case of reference to function
543
+ // parameters that the surrounding function hasn't been instantiated yet. Note
544
+ // this may happen while we're comparing two templates' constraint
545
+ // equivalence.
546
+ LocalInstantiationScope ScopeForParameters (S);
547
+ if (auto *FD = DeclInfo.getDecl ()->getAsFunction ())
548
+ for (auto *PVD : FD->parameters ())
549
+ ScopeForParameters.InstantiatedLocal (PVD, PVD);
550
+
551
+ std::optional<Sema::CXXThisScopeRAII> ThisScope;
552
+
553
+ // See TreeTransform::RebuildTemplateSpecializationType. A context scope is
554
+ // essential for having an injected class as the canonical type for a template
555
+ // specialization type at the rebuilding stage. This guarantees that, for
556
+ // out-of-line definitions, injected class name types and their equivalent
557
+ // template specializations can be profiled to the same value, which makes it
558
+ // possible that e.g. constraints involving C<Class<T>> and C<Class> are
559
+ // perceived identical.
560
+ std::optional<Sema::ContextRAII> ContextScope;
561
+ if (auto *RD = dyn_cast<CXXRecordDecl>(DeclInfo.getDeclContext ())) {
562
+ ThisScope.emplace (S, const_cast <CXXRecordDecl *>(RD), Qualifiers ());
563
+ ContextScope.emplace (S, const_cast <DeclContext *>(cast<DeclContext>(RD)),
564
+ /* NewThisContext=*/ false );
565
+ }
566
+
567
+ EnterExpressionEvaluationContext ConstantEvaluated (
568
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
569
+
570
+ ExprResult SubstExceptionSpec =
571
+ S.SubstExpr (const_cast <clang::Expr *>(ExceptionSpec), MLTAL);
572
+ if (SFINAE.hasErrorOccurred () || !SubstExceptionSpec.isUsable ())
573
+ return nullptr ;
574
+ return SubstExceptionSpec.get ();
575
+ }
576
+
577
+ bool Sema::AreExceptionSpecsEqual (const NamedDecl *Old,
578
+ const Expr *OldExceptionSpec,
579
+ const NamedDecl *New,
580
+ const Expr *NewExceptionSpec) {
581
+ if (OldExceptionSpec == NewExceptionSpec)
582
+ return true ;
583
+ if (Old && New &&
584
+ Old->getLexicalDeclContext () != New->getLexicalDeclContext ()) {
585
+ if (const Expr *SubstExceptionSpec =
586
+ SubstituteExceptionSpecWithoutEvaluation (*this , Old,
587
+ OldExceptionSpec))
588
+ OldExceptionSpec = SubstExceptionSpec;
589
+ else
590
+ return false ;
591
+ if (const Expr *SubstExceptionSpec =
592
+ SubstituteExceptionSpecWithoutEvaluation (*this , New,
593
+ NewExceptionSpec))
594
+ NewExceptionSpec = SubstExceptionSpec;
595
+ else
596
+ return false ;
597
+ }
598
+
599
+ llvm::FoldingSetNodeID ID1, ID2;
600
+ OldExceptionSpec->Profile (ID1, Context, /* Canonical=*/ true );
601
+ NewExceptionSpec->Profile (ID2, Context, /* Canonical=*/ true );
602
+ return ID1 == ID2;
603
+ }
604
+
504
605
// / CheckEquivalentExceptionSpec - Check if the two types have compatible
505
606
// / exception specifications. See C++ [except.spec]p3.
506
607
// /
@@ -574,6 +675,7 @@ static bool CheckEquivalentExceptionSpecImpl(
574
675
}
575
676
}
576
677
678
+ #if 0
577
679
// C++14 [except.spec]p3:
578
680
// Two exception-specifications are compatible if [...] both have the form
579
681
// noexcept(constant-expression) and the constant-expressions are equivalent
@@ -584,6 +686,7 @@ static bool CheckEquivalentExceptionSpecImpl(
584
686
if (OldFSN == NewFSN)
585
687
return false;
586
688
}
689
+ #endif
587
690
588
691
// Dynamic exception specifications with the same set of adjusted types
589
692
// are compatible.
0 commit comments