summaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
AgeCommit message (Collapse)Author
2025-11-11[clang-tidy] Add `IgnoreValueCalls` option to ↵mitchell
bugprone-unchecked-optional-access (#167209) Add a new option `IgnoreValueCalls` to `bugprone-unchecked-optional-access` Closes [#163831](https://github.com/llvm/llvm-project/issues/163831)
2025-10-20[FlowSensitive] [Optional] Fix absl::in_place (#163897)Florian Mayer
The mock was not accurate, absl defines in_place[_t] as an alias to std::in_place[_t].
2025-09-09[clang-tidy] `bugprone-unchecked-optional-access`: handle ↵Valentyn Yukhymenko
`BloombergLP::bdlb:NullableValue::makeValue` to prevent false-positives (#144313) https://github.com/llvm/llvm-project/pull/101450 added support for `BloombergLP::bdlb::NullableValue`. However, `NullableValue::makeValue` and `NullableValue::makeValueInplace` have been missed which impacts code like this: ```cpp if (opt.isNull()) { opt.makeValue(42); } opt.value(); // triggers false positive warning from `bugprone-unchecked-optional-access` ``` My patch addresses this issue. [Docs that I used for methods mocks](https://bloomberg.github.io/bde-resources/doxygen/bde_api_prod/classbdlb_1_1NullableValue.html) --------- Co-authored-by: Baranov Victor <bar.victor.2002@gmail.com>
2025-08-27[clang] NFC: reintroduce clang/include/clang/AST/Type.h (#155050)Matheus Izvekov
This reintroduces `Type.h`, having earlier been renamed to `TypeBase.h`, as a redirection to `TypeBase.h`, and redirects most users to include the former instead. This is a preparatory patch for being able to provide inline definitions for `Type` methods which would otherwise cause a circular dependency with `Decl{,CXX}.h`. Doing these operations into their own NFC patch helps the git rename detection logic work, preserving the history. This patch makes clang just a little slower to build (~0.17%), just because it makes more code indirectly include `DeclCXX.h`.
2025-08-27[clang] NFC: rename clang/include/clang/AST/Type.h to TypeBase.h (#155049)Matheus Izvekov
This is a preparatory patch, to be able to provide inline definitions for `Type` functions which depend on `Decl{,CXX}.h`. As the latter also depends on `Type.h`, this would not be possible without some reorganizing. Splitting this rename into its own patch allows git to track this as a rename, and preserve all git history, and not force any code reformatting. A later NFC patch will reintroduce `Type.h` as redirection to `TypeBase.h`, rewriting most places back to directly including `Type.h` instead of `TypeBase.h`, leaving only a handful of places where this is necessary. Then yet a later patch will exploit this by making more stuff inline.
2025-05-31[Analysis] Remove unused includes (NFC) (#142255)Kazu Hirata
These are identified by misc-include-cleaner. I've filtered out those that break builds. Also, I'm staying away from llvm-config.h, config.h, and Compiler.h, which likely cause platform- or compiler-specific build failures.
2025-03-17[clang][dataflow] For bugprone-unchecked-optional-access report range (#131055)Jan Voung
Report the range in diagnostics, in addition to the location in case the range helps disambiguate a little in chained `->` expressions. ``` b->a->f->x = 1; ^~~~~~~ ``` instead of just: ``` b->a->f->x = 1; ^ ``` As a followup we should probably also report the location/range of an `->` if that operator is used. Like: ``` b->a->f->x = 1; ^~ ```
2025-03-07[clang][dataflow] Add test for crash repro and clean up const accessor ↵Jan Voung
handling (#129930) Add test for https://github.com/llvm/llvm-project/issues/125589 The crash is actually incidentally fixed by https://github.com/llvm/llvm-project/pull/128437 since it added a branch for the reference case and would no longer fall through when the return type is a reference to a pointer. Clean up a bit as well: - make the fallback for early returns more consistent (check if returning optional and call transfer function for that case) - check RecordLoc == nullptr in one place - clean up extra spaces in test - clean up parameterization in test of `std::` vs `$ns::$`
2025-02-28[clang-tidy] [dataflow] Cache reference accessors for ↵Valentyn Yukhymenko
`bugprone-unchecked-optional-access` (#128437) Fixes https://github.com/llvm/llvm-project/issues/126283 Extending https://github.com/llvm/llvm-project/pull/112605 to cache const getters which return references. Fixes false positives from const reference accessors to object containing optional member
2025-01-08[clang][dataflow] Use smart pointer caching in unchecked optional accessor ↵Jan Voung
(#120249) Part 2 (and final part) following https://github.com/llvm/llvm-project/pull/120102 Allows users to do things like: ``` if (o->x.has_value()) { ((*o).x).value(); } ``` where the `->` and `*` are operator overload calls. A user could instead extract the nested optional into a local variable once instead of doing two accessor calls back to back, but currently they are unsure why the code is flagged.
2024-10-28[clang][dataflow] Cache accessors returning pointers in ↵Jan Voung
bugprone-unchecked-optional-access (#113922) Previously, we covered returning refs, or copies of optional, and bools. Now cover returning pointers (to any type). This is useful for cases like operator-> of smart pointers. Addresses more of issue llvm#58510
2024-10-28[clang][dataflow] Don't clear cached field state if field is const (#113698)Jan Voung
... in the unchecked optional access model.
2024-10-22[clang][dataflow] Cache accessors for bugprone-unchecked-optional-access ↵Jan Voung
(#112605) Treat calls to zero-param const methods as having stable return values (with a cache) to address issue #58510. The cache is invalidated when non-const methods are called. This uses the infrastructure from PR #111006. For now we cache methods returning: - ref to optional - optional by value - booleans We can extend that to pointers to optional in a next change.
2024-09-25[clang-tidy] Add support for bsl::optional (#101450)Chris Cotter
2024-04-19[clang][nullability] Remove `RecordValue`. (#89052)martinboehme
This class no longer serves any purpose; see also the discussion here: https://reviews.llvm.org/D155204#inline-1503204 A lot of existing tests in TransferTest.cpp check for the existence of `RecordValue`s. Some of these checks are now simply redundant and have been removed. In other cases, tests were checking for the existence of a `RecordValue` as a way of testing whether a record has been initialized. I have typically changed these test to instead check whether a field of the record has a value.
2024-03-28[clang][dataflow] Fix for value constructor in class derived from optional. ↵martinboehme
(#86942) The constructor `Derived(int)` in the newly added test `ClassDerivedFromOptionalValueConstructor` is not a template, and this used to cause an assertion failure in `valueOrConversionHasValue()` because `F.getTemplateSpecializationArgs()` returns null. (This is modeled after the `MaybeAlign(Align Value)` constructor, which similarly causes an assertion failure in the analysis when assigning an `Align` to a `MaybeAlign`.) To fix this, we can simply look at the type of the destination type which we're constructing or assigning to (instead of the function template argument), and this not only fixes this specific case but actually simplifies the implementation. I've added some additional tests for the case of assigning to a nested optional because we didn't have coverage for these and I wanted to make sure I didn't break anything.
2024-03-19[clang][dataflow] Make optional checker work for types derived from ↵martinboehme
optional. (#84138) `llvm::MaybeAlign` does this, for example. It's not an option to simply ignore these derived classes because they get cast back to the optional classes (for example, simply when calling the optional member functions), and our transfer functions will then run on those optional classes and therefore require them to be properly initialized.
2023-12-21[clang][dataflow] Add `Environment::get<>()`. (#76027)martinboehme
This template function casts the result of `getValue()` or `getStorageLocation()` to a given subclass of `Value` or `StorageLocation` (using `cast_or_null`). It's a common pattern to do something like this: ```cxx auto *Val = cast_or_null<PointerValue>(Env.getValue(E)); ``` This can now be expressed more concisely like this: ```cxx auto *Val = Env.get<PointerValue>(E); ``` Instead of adding a new method `get()`, I had originally considered simply adding a template parameter to `getValue()` and `getStorageLocation()` (with a default argument of `Value` or `StorageLocation`), but this results in an undesirable repetition at the callsite, e.g. `getStorageLocation<RecordStorageLocation>(...)`. The `Value` and `StorageLocation` in the method name adds nothing of value when the template argument already contains this information, so it seemed best to shorten the method name to simply `get()`.
2023-12-04[clang][dataflow] Add synthetic fields to `RecordStorageLocation` (#73860)martinboehme
Synthetic fields are intended to model the internal state of a class (e.g. the value stored in a `std::optional`) without having to depend on that class's implementation details. Today, this is typically done with properties on `RecordValue`s, but these have several drawbacks: * Care must be taken to call `refreshRecordValue()` before modifying a property so that the modified property values aren’t seen by other environments that may have access to the same `RecordValue`. * Properties aren’t associated with a storage location. If an analysis needs to associate a location with the value stored in a property (e.g. to model the reference returned by `std::optional::value()`), it needs to manually add an indirection using a `PointerValue`. (See for example the way this is done in UncheckedOptionalAccessModel.cpp, specifically in `maybeInitializeOptionalValueMember()`.) * Properties don’t participate in the builtin compare, join, and widen operations. If an analysis needs to apply these operations to properties, it needs to override the corresponding methods of `ValueModel`. * Longer-term, we plan to eliminate `RecordValue`, as by-value operations on records aren’t really “a thing” in C++ (see https://discourse.llvm.org/t/70086#changed-structvalue-api-14). This would obviously eliminate the ability to set properties on `RecordValue`s. To demonstrate the advantages of synthetic fields, this patch converts UncheckedOptionalAccessModel.cpp to synthetic fields. This greatly simplifies the implementation of the check. This PR is pretty big; to make it easier to review, I have broken it down into a stack of three commits, each of which contains a set of logically related changes. I considered submitting each of these as a separate PR, but the commits only really make sense when taken together. To review, I suggest first looking at the changes in UncheckedOptionalAccessModel.cpp. This gives a flavor for how the various API changes work together in the context of an analysis. Then, review the rest of the changes.
2023-10-30[clang][nullability] Use `proves()` and `assume()` instead of deprecated ↵martinboehme
synonyms. (#70297)
2023-10-21[clang][dataflow]Use cast_or_null instead of cast to prevent crash (#68510)Qizhi Hu
`getStorageLocation` may return `nullptr` and this will produce crash when use `cast`, use `dyn_cast_or_null` instead. I test it locally using [FTXUI](https://github.com/ArthurSonzogni/FTXUI) and it may be the cause of issue [issue](https://github.com/llvm/llvm-project/issues/68412), but I am not sure. Co-authored-by: huqizhi <huqizhi@836744285@qq.com>
2023-09-13[clang][dataflow] Change `diagnoseFunction` to use `llvm::SmallVector` ↵Yitzhak Mandelbaum
instead of `std::vector`. (#66014) The template is agnostic as to the type used by the list, as long as it is compatible with `llvm::move` and `std::back_inserter`. In practice, we've encountered analyses which use different types (`llvm::SmallVector` vs `std::vector`), so it seems preferable to leave this open to the caller.
2023-08-29[clang][dataflow] Don't associate prvalue expressions with storage locations.Martin Braenne
Instead, map prvalue expressions directly to values in a newly introduced map `Environment::ExprToVal`. This change introduces an additional member variable in `Environment` but is an overall win: - It is more conceptually correctly, since prvalues don't have storage locations. - It eliminates complexity from `Environment::setValue(const Expr &E, Value &Val)`. - It reduces the amount of data stored in `Environment`: A prvalue now has a single entry in `ExprToVal` instead of one in `ExprToLoc` and one in `LocToVal`. - Not allocating `StorageLocation`s for prvalues additionally reduces memory usage. This patch is the last step in the migration to strict handling of value categories (see https://discourse.llvm.org/t/70086 for details). The changes here are almost entirely internal to `Environment`. The only externally observable change is that when associating a `RecordValue` with the location returned by `Environment::getResultObjectLocation()` for a given expression, callers additionally need to associate the `RecordValue` with the expression themselves. Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D158977
2023-08-01[clang][dataflow] Rename `AggregateStorageLocation` to ↵Martin Braenne
`RecordStorageLocation` and `StructValue` to `RecordValue`. - Both of these constructs are used to represent structs, classes, and unions; Clang uses the collective term "record" for these. - The term "aggregate" in `AggregateStorageLocation` implies that, at some point, the intention may have been to use it also for arrays, but it don't think it's possible to use it for arrays. Records and arrays are very different and therefore need to be modeled differently. Records have a fixed set of named fields, which can have different type; arrays have a variable number of elements, but they all have the same type. - Futhermore, "aggregate" has a very specific meaning in C++ (https://en.cppreference.com/w/cpp/language/aggregate_initialization). Aggregates of class type may not have any user-declared or inherited constructors, no private or protected non-static data members, no virtual member functions, and so on, but we use `AggregateStorageLocations` to model all objects of class type. In addition, for consistency, we also rename the following: - `getAggregateLoc()` (in `RecordValue`, formerly known as `StructValue`) to simply `getLoc()`. - `refreshStructValue()` to `refreshRecordValue()` We keep the old names around as deprecated synonyms to enable clients to be migrated to the new names. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D156788
2023-07-31[clang][dataflow] Remove `Strict` suffix from accessors.Martin Braenne
For the time being, we're keeping the `Strict` versions around as deprecated synonyms so that clients can be migrated, but these synonyms will be removed soon. Depends On D156673 Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D156674
2023-07-31[clang][dataflow] Use `Strict` accessors where we weren't using them yet.Martin Braenne
This eliminates all uses of the deprecated accessors. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D156672
2023-07-27[clang][dataflow] Reverse course on `getValue()` deprecation.Martin Braenne
In the [value categories RFC](https://discourse.llvm.org/t/70086), I proposed that the end state of the migration should be that `getValue()` should only be legal to call on prvalues. As a stepping stone, to allow migrating off existing calls to `getValue()`, I proposed introducing `getValueStrict()`, which would already have the new semantics. However, I've now reconsidered this. Any expression, whether prvalue or glvalue, has a value, so really there isn't any reason to forbid calling `getValue()` on glvalues. I'm therefore removing the deprecation from `getValue()` and transitioning existing `getValueStrict()` calls back to `getValue()`. The other "strict" accessors are a different case. `setValueStrict()` should only be called on prvalues because glvalues need to have a storage location associated with them; it doesn't make sense to only set a value for them. And, of course, `getStorageLocationStrict()` and `setStorageLocationStrict()` should obviously only be called on glvalues because prvalues don't have storage locations. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D155921
2023-07-26[clang-tidy] Update unchecked-optiona-access-check to use convenience ↵Yitzhak Mandelbaum
function for diagnosing `FunctionDecl`s. Also changes code in the underlying model to fit the type expected by the convenience function. Differential Revision: https://reviews.llvm.org/D156255
2023-07-24[clang-tidy] Add folly::Optional to unchecked-optional-accessAnton Dukeman
The unchecked-optional-access check identifies attempted value unwrapping without checking if the value exists. These changes extend that support to checking folly::Optional. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D155890
2023-07-24[clang][dataflow] Eliminate duplication between `AggregateStorageLocation` ↵Martin Braenne
and `StructValue`. After this change, `StructValue` is just a wrapper for an `AggregateStorageLocation`. For the wider context, see https://discourse.llvm.org/t/70086. ## How to review - Start by looking at the comments added / changed in Value.h, StorageLocation.h, and DataflowEnvironment.h. This will give you a good overview of the semantic changes. - Look at the corresponding .cpp files that implement the semantic changes. - Transfer.cpp, TypeErasedDataflowAnalysis.cpp, and RecordOps.cpp show how the core of the framework is affected by the semantic changes. - UncheckedOptionalAccessModel.cpp shows how this complex model is affected by the changes. - Many of the changes in the rest of the patch are mechanical in nature. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D155446
2023-07-17[clang][dataflow] Simplify implementation of `transferStdForwardCall()` in ↵Martin Braenne
optional check. The argument and return value of `std::forward` is always a reference, so we can simply forward the storage location. Depends On D155075 Reviewed By: ymandel, gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D155202
2023-07-13[dataflow] Remove deprecated BoolValue flow condition accessorsSam McCall
Use the Formula versions instead, now. Differential Revision: https://reviews.llvm.org/D155152
2023-07-10[clang][dataflow] Various refactorings to UncheckedOptionalAccessModel.Martin Braenne
These are intended to ease an upcoming change that will eliminate the duplication between `AggregateStorageLocation` and `StructValue` (see https://discourse.llvm.org/t/70086 for details), but many of the changes also have value in their own right. Depends On D154586 Reviewed By: ymandel, gribozavr2 Differential Revision: https://reviews.llvm.org/D154597
2023-06-12[clang][dataflow][NFC] Expand comments on losing values in optional checker.Martin Braenne
While working on the ongoing migration to strict handling of value categories (see https://discourse.llvm.org/t/70086), I ran into issues related to losing the value associated with an optional. This issue is hinted at in the existing comments, but the issue didn't become sufficiently clear to me from those, so I thought it would be worth capturing more details, along with ideas for how this issue might be fixed. Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D152369
2023-06-05[clang][dataflow] Use a `PointerValue` for `value` property in optional checker.Martin Braenne
The `ReferenceValue` class will be eliminated as part of the ongoing migration to strict handling of value categories (see https://discourse.llvm.org/t/70086 for details). Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D152144
2023-05-22[clang][dataflow] Fix a bug in handling of `operator->` for optional checker.Martin Braenne
Prior to this patch, `operator->` was being handled like `operator*`: It was associating a `Value` of type `T` with the expression result (where `T` is the template argument of the `optional<T>`). This is correct for `operator*`, which returns a reference (of some flavor) to `T`, so that the result of the `CXXOperatorCallExpr` is a glvalue of type `T`. However, `operator*` returns a `T*`, so the result of the `CXXOperatorCallExpr` is a prvalue `T*`, which should therefore be associated with `PointerValue` that in turn refers to a `T`. I noticed this issue while working on the migration to strict handling of value categories (see https://discourse.llvm.org/t/70086). The current behavior also seems problematic more generally because it's plausible that the framework may at some point introduce behavior that assumes an `Expr` of pointer type is always associated with a `PointerValue`. As it turns out, this patch fixes an existing FIXME in the test `OptionalValueInitialization`. Depends On D150657 Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D150775
2023-05-17[clang][dataflow] Remove unused parameter from `diagnoseUnwrapCall()`.Martin Braenne
Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D150756
2023-05-17[ClangTidy] Fix markup in commentsDmitri Gribenko
2023-05-15[clang][dataflow] Eliminate `SkipPast::ReferenceThenPointer`.Martin Braenne
As a replacement, we provide the accessors `getImplicitObjectLocation()` and `getBaseObjectLocation()`, which are higher-level constructs that cover the use cases in which `SkipPast::ReferenceThenPointer` was typically used. Unfortunately, it isn't possible to use these accessors in UncheckedOptionalAccessModel.cpp; I've added a FIXME to the code explaining the details. I initially attempted to resolve the issue as part of this patch, but it turned out to be non-trivial to fix. Instead, I have therefore added a lower-level replacement for `SkipPast::ReferenceThenPointer` that is used only within this file. The wider context of this change is that `SkipPast` will be going away entirely. See also the RFC at https://discourse.llvm.org/t/70086. Reviewed By: ymandel, gribozavr2 Differential Revision: https://reviews.llvm.org/D149838
2023-05-04[clang][dataflow][NFC] Eliminate unnecessary helper `stripReference()`.Martin Braenne
`QualType::getNonReferenceType()` does the same thing. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D149744
2023-04-17[clang][dataflow] Drop optional model's dependency on libc++ internals.Yitzhak Mandelbaum
Adjusts the matchers in the optional model to avoid dependency on internal implementation details of libc++'s `std::optional`. In the process, factors out the code to check the name of these types so that it's shared throughout. Differential Revision: https://reviews.llvm.org/D148377
2023-04-17[clang][dataflow] Refine matching of optional types to anchor at top level.Yitzhak Mandelbaum
This patch refines the matching of the relevant optional types to anchor on the global namespace. Previously, we could match anything with the right name (e.g. `base::Optional`) even if nested within other namespaces. This over matching resulted in an assertion violation when _different_ `base::Optional` was encountered nested inside another namespace. Fixes issue #57036. Differential Revision: https://reviews.llvm.org/D148344
2023-04-04[clang-tidy] Allow bugprone-unchecked-optional-access to handle calls to ↵AMS21
`std::forward` The check now understands that calling `std::forward` will not modify the underlying optional value. This fixes llvm#59705 Reviewed By: PiotrZSL Differential Revision: https://reviews.llvm.org/D147383
2023-04-04[clang][dataflow] Add `create<T>()` methods to `Environment` and ↵Martin Braenne
`DataflowAnalysisContext`. These methods provide a less verbose way of allocating `StorageLocation`s and `Value`s than the existing `takeOwnership(make_unique(...))` pattern. In addition, because allocation of `StorageLocation`s and `Value`s now happens within the `DataflowAnalysisContext`, the `create<T>()` open up the possibility of using `BumpPtrAllocator` to allocate these objects if it turns out this helps performance. Reviewed By: ymandel, xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D147302
2023-02-15[clang][dataflow] Change `transfer` API to take a reference.Yitzhak Mandelbaum
The provided `CFGElement` is never null, so a reference is a more precise type. Differential Revision: https://reviews.llvm.org/D143920
2023-02-01[clang][dataflow] Relax validity assumptions in `UncheckedOptionalAccessModel`.Yitzhak Mandelbaum
Currently, the interpretation of `swap` calls in the optional model assumes the optional arguments are modeled (and therefore have valid storage locations and values). This assumption is incorrect, for example, in the case of unmodeled optional fields (which can be missing either value or location). This patch relaxes these assumptions, to return rather than assert when either argument is not modeled. Differential Revision: https://reviews.llvm.org/D142710
2023-01-14[clang] Use std::optional instead of llvm::Optional (NFC)Kazu Hirata
This patch replaces (llvm::|)Optional< with std::optional<. I'll post a separate patch to remove #include "llvm/ADT/Optional.h". This is part of an effort to migrate from llvm::Optional to std::optional: https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2023-01-14[clang] Add #include <optional> (NFC)Kazu Hirata
This patch adds #include <optional> to those files containing llvm::Optional<...> or Optional<...>. I'll post a separate patch to actually replace llvm::Optional with std::optional. This is part of an effort to migrate from llvm::Optional to std::optional: https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2023-01-12[clang][dataflow] In optional model, implement `widen` and make `compare` sound.Yitzhak Mandelbaum
This patch includes two related changes: 1. Rewrite `compare` operation to be sound. Current version checks for equality of `isNonEmptyOptional` on both values, judging the values `Same` when the results are equal. While that works when both are true, it is problematic when they are both false, because there are four cases in which that's can occur: both empty, one empty and one unknown (which is two cases), and both unknown. In the latter three cases, it is unsound to judge them `Same`. This patch changes `compare` to explicitly check for case of `both empty` and then judge any other case `Different`. 2. With the change to `compare`, a number of common cases will no longer terminate. So, we also implement widening to properly handle those cases and recover termination. Drive-by: improve performance of `merge` operation. Of the new tests, the code before the patch fails * ReassignValueInLoopToSetUnsafe, and * ReassignValueInLoopToUnknownUnsafe. Differential Revision: https://reviews.llvm.org/D140344
2023-01-03[clang][dataflow] Fix bug in optional-checker's handling of nullopt constructor.Yitzhak Mandelbaum
Currently, the checker only recognizes the nullopt constructor when it is called without sugar, resulting in a crash in the (rare) case where it has been wrapped in sugar. This relaxes the constraint by checking the constructor decl directly (which always contains the same, desugared form) rather than the construct expression (where the spelling depends on the context). Differential Revision: https://reviews.llvm.org/D140921