Skip to content

Commit 989f76c

Browse files
committed
[clang] template / auto deduction deduces common sugar
After upgrading the type deduction machinery to retain type sugar in D110216, we were left with a situation where there is no general well behaved mechanism in Clang to unify the type sugar of multiple deductions of the same type parameter. So we ended up making an arbitrary choice: keep the sugar of the first deduction, ignore subsequent ones. In general, we already had this problem, but in a smaller scale. The result of the conditional operator and many other binary ops could benefit from such a mechanism. This patch implements such a type sugar unification mechanism. The basics: This patch introduces a `getCommonSugaredType(QualType X, QualType Y)` method to ASTContext which implements this functionality, and uses it for unifying the results of type deduction and return type deduction. This will return the most derived type sugar which occurs in both X and Y. Example: Suppose we have these types: ``` using Animal = int; using Cat = Animal; using Dog = Animal; using Tom = Cat; using Spike = Dog; using Tyke = Dog; ``` For `X = Tom, Y = Spike`, this will result in `Animal`. For `X = Spike, Y = Tyke`, this will result in `Dog`. How it works: We take two types, X and Y, which we wish to unify as input. These types must have the same (qualified or unqualified) canonical type. We dive down fast through top-level type sugar nodes, to the underlying canonical node. If these canonical nodes differ, we build a common one out of the two, unifying any sugar they had. Note that this might involve a recursive call to unify any children of those. We then return that canonical node, handling any qualifiers. If they don't differ, we walk up the list of sugar type nodes we dived through, finding the last identical pair, and returning that as the result, again handling qualifiers. Note that this patch will not unify sugar nodes if they are not identical already. We will simply strip off top-level sugar nodes that differ between X and Y. This sugar node unification will instead be implemented in a subsequent patch. This patch also implements a few users of this mechanism: * Template argument deduction. * Auto deduction, for functions returning auto / decltype(auto), with special handling for initializer_list as well. Further users will be implemented in a subsequent patch. Signed-off-by: Matheus Izvekov <[email protected]> Differential Revision: https://reviews.llvm.org/D111283
1 parent 5871f18 commit 989f76c

File tree

18 files changed

+1122
-1295
lines changed

18 files changed

+1122
-1295
lines changed

clang-tools-extra/clangd/unittests/ASTTests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
8484
8585
^auto i = {1,2};
8686
)cpp",
87-
"class std::initializer_list<int>",
87+
"std::initializer_list<int>",
8888
},
8989
{
9090
R"cpp( // auto in function return type with trailing return type

clang-tools-extra/clangd/unittests/HoverTests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1991,7 +1991,7 @@ TEST(Hover, All) {
19911991
[](HoverInfo &HI) {
19921992
HI.Name = "auto";
19931993
HI.Kind = index::SymbolKind::TypeAlias;
1994-
HI.Definition = "class std::initializer_list<int>";
1994+
HI.Definition = "std::initializer_list<int>";
19951995
}},
19961996
{
19971997
R"cpp(// User defined conversion to auto

clang/include/clang/AST/ASTContext.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2537,6 +2537,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
25372537
return getCanonicalType(T1) == getCanonicalType(T2);
25382538
}
25392539

2540+
/// Determine whether the given expressions \p X and \p Y are equivalent.
2541+
bool hasSameExpr(const Expr *X, const Expr *Y) const;
2542+
25402543
/// Return this type as a completely-unqualified array type,
25412544
/// capturing the qualifiers in \p Quals.
25422545
///
@@ -2807,6 +2810,23 @@ class ASTContext : public RefCountedBase<ASTContext> {
28072810
return AddrSpaceMapMangling || isTargetAddressSpace(AS);
28082811
}
28092812

2813+
// Merges two exception specifications, such that the resulting
2814+
// exception spec is the union of both. For example, if either
2815+
// of them can throw something, the result can throw it as well.
2816+
FunctionProtoType::ExceptionSpecInfo
2817+
mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1,
2818+
FunctionProtoType::ExceptionSpecInfo ESI2,
2819+
SmallVectorImpl<QualType> &ExceptionTypeStorage,
2820+
bool AcceptDependent);
2821+
2822+
// For two "same" types, return a type which has
2823+
// the common sugar between them. If Unqualified is true,
2824+
// both types need only be the same unqualified type.
2825+
// The result will drop the qualifiers which do not occur
2826+
// in both types.
2827+
QualType getCommonSugaredType(QualType X, QualType Y,
2828+
bool Unqualified = false);
2829+
28102830
private:
28112831
// Helper for integer ordering
28122832
unsigned getIntegerRank(const Type *T) const;

clang/include/clang/AST/Type.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4320,10 +4320,9 @@ class FunctionProtoType final
43204320
}
43214321

43224322
using param_type_iterator = const QualType *;
4323-
using param_type_range = llvm::iterator_range<param_type_iterator>;
43244323

4325-
param_type_range param_types() const {
4326-
return param_type_range(param_type_begin(), param_type_end());
4324+
ArrayRef<QualType> param_types() const {
4325+
return llvm::makeArrayRef(param_type_begin(), param_type_end());
43274326
}
43284327

43294328
param_type_iterator param_type_begin() const {

clang/include/clang/Sema/Sema.h

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8771,7 +8771,9 @@ class Sema final {
87718771
/// Deduction failed; that's all we know.
87728772
TDK_MiscellaneousDeductionFailure,
87738773
/// CUDA Target attributes do not match.
8774-
TDK_CUDATargetMismatch
8774+
TDK_CUDATargetMismatch,
8775+
/// Some error which was already diagnosed.
8776+
TDK_AlreadyDiagnosed
87758777
};
87768778

87778779
TemplateDeductionResult
@@ -8862,21 +8864,11 @@ class Sema final {
88628864
TypeSourceInfo *ReplaceAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
88638865
QualType Replacement);
88648866

8865-
/// Result type of DeduceAutoType.
8866-
enum DeduceAutoResult {
8867-
DAR_Succeeded,
8868-
DAR_Failed,
8869-
DAR_FailedAlreadyDiagnosed
8870-
};
8871-
8872-
DeduceAutoResult
8873-
DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result,
8874-
Optional<unsigned> DependentDeductionDepth = None,
8875-
bool IgnoreConstraints = false);
8876-
DeduceAutoResult
8877-
DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result,
8878-
Optional<unsigned> DependentDeductionDepth = None,
8879-
bool IgnoreConstraints = false);
8867+
TemplateDeductionResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *Initializer,
8868+
QualType &Result,
8869+
sema::TemplateDeductionInfo &Info,
8870+
bool DependentDeduction = false,
8871+
bool IgnoreConstraints = false);
88808872
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
88818873
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
88828874
bool Diagnose = true);
@@ -8898,8 +8890,8 @@ class Sema final {
88988890
TypeLoc getReturnTypeLoc(FunctionDecl *FD) const;
88998891

89008892
bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
8901-
SourceLocation ReturnLoc,
8902-
Expr *&RetExpr, const AutoType *AT);
8893+
SourceLocation ReturnLoc, Expr *RetExpr,
8894+
const AutoType *AT);
89038895

89048896
FunctionTemplateDecl *getMoreSpecializedTemplate(
89058897
FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,

0 commit comments

Comments
 (0)