forked from OSchip/llvm-project
[clang] fix frontend crash when evaluating type trait
Before this patch type traits are checked in Parser, so use type traits directly did not cause assertion faults. However if type traits are initialized from a template, we didn't perform arity checks before evaluating. This patch moves arity checks from Parser to Sema, and performing arity checks in Sema actions, so type traits get checked corretly. Crash input: ``` template<class... Ts> bool b = __is_constructible(Ts...); bool x = b<>; ``` After this patch: ``` clang/test/SemaCXX/type-trait-eval-crash-issue-57008.cpp:5:32: error: type trait requires 1 or more arguments; have 0 arguments template<class... Ts> bool b = __is_constructible(Ts...); ^~~~~~~~~~~~~~~~~~ clang/test/SemaCXX/type-trait-eval-crash-issue-57008.cpp:6:10: note: in instantiation of variable template specialization 'b<>' requested here bool x = b<>; ^ 1 error generated. ``` See https://godbolt.org/z/q39W78hsK. Fixes https://github.com/llvm/llvm-project/issues/57008 Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D131423
This commit is contained in:
parent
4b45999bdd
commit
e5825190b8
|
@ -68,6 +68,9 @@ Bug Fixes
|
|||
- Fixed a crash-on-valid with consteval evaluation of a list-initialized
|
||||
constructor for a temporary object. This fixes
|
||||
`Issue 55871 <https://github.com/llvm/llvm-project/issues/55871>`_.
|
||||
- Fix `#57008 <https://github.com/llvm/llvm-project/issues/57008>`_ - Builtin
|
||||
C++ language extension type traits instantiated by a template with unexpected
|
||||
number of arguments cause an assertion fault.
|
||||
|
||||
Improvements to Clang's diagnostics
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -67,6 +67,10 @@ const char *getTraitName(UnaryExprOrTypeTrait T) LLVM_READONLY;
|
|||
const char *getTraitSpelling(TypeTrait T) LLVM_READONLY;
|
||||
const char *getTraitSpelling(ArrayTypeTrait T) LLVM_READONLY;
|
||||
const char *getTraitSpelling(UnaryExprOrTypeTrait T) LLVM_READONLY;
|
||||
|
||||
/// Return the arity of the type trait \p T.
|
||||
unsigned getTypeTraitArity(TypeTrait T) LLVM_READONLY;
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5552,6 +5552,8 @@ public:
|
|||
bool isQualifiedMemberAccess(Expr *E);
|
||||
QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc);
|
||||
|
||||
bool CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N);
|
||||
|
||||
ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
|
||||
SourceLocation OpLoc,
|
||||
UnaryExprOrTypeTrait ExprKind,
|
||||
|
|
|
@ -55,6 +55,15 @@ static constexpr const char *UnaryExprOrTypeTraitSpellings[] = {
|
|||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
|
||||
static constexpr const unsigned TypeTraitArities[] = {
|
||||
#define TYPE_TRAIT_1(Spelling, Name, Key) 1,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#define TYPE_TRAIT_2(Spelling, Name, Key) 2,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#define TYPE_TRAIT_N(Spelling, Name, Key) 0,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
|
||||
const char *clang::getTraitName(TypeTrait T) {
|
||||
assert(T <= TT_Last && "invalid enum value!");
|
||||
return TypeTraitNames[T];
|
||||
|
@ -84,3 +93,8 @@ const char *clang::getTraitSpelling(UnaryExprOrTypeTrait T) {
|
|||
assert(T <= UETT_Last && "invalid enum value!");
|
||||
return UnaryExprOrTypeTraitSpellings[T];
|
||||
}
|
||||
|
||||
unsigned clang::getTypeTraitArity(TypeTrait T) {
|
||||
assert(T <= TT_Last && "invalid enum value!");
|
||||
return TypeTraitArities[T];
|
||||
}
|
||||
|
|
|
@ -3724,14 +3724,6 @@ static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) {
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned TypeTraitArity(tok::TokenKind kind) {
|
||||
switch (kind) {
|
||||
default: llvm_unreachable("Not a known type trait");
|
||||
#define TYPE_TRAIT(N,Spelling,K) case tok::kw_##Spelling: return N;
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the built-in type-trait pseudo-functions that allow
|
||||
/// implementation of the TR1/C++11 type traits templates.
|
||||
///
|
||||
|
@ -3745,7 +3737,6 @@ static unsigned TypeTraitArity(tok::TokenKind kind) {
|
|||
///
|
||||
ExprResult Parser::ParseTypeTrait() {
|
||||
tok::TokenKind Kind = Tok.getKind();
|
||||
unsigned Arity = TypeTraitArity(Kind);
|
||||
|
||||
SourceLocation Loc = ConsumeToken();
|
||||
|
||||
|
@ -3780,18 +3771,6 @@ ExprResult Parser::ParseTypeTrait() {
|
|||
|
||||
SourceLocation EndLoc = Parens.getCloseLocation();
|
||||
|
||||
if (Arity && Args.size() != Arity) {
|
||||
Diag(EndLoc, diag::err_type_trait_arity)
|
||||
<< Arity << 0 << (Arity > 1) << (int)Args.size() << SourceRange(Loc);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
if (!Arity && Args.empty()) {
|
||||
Diag(EndLoc, diag::err_type_trait_arity)
|
||||
<< 1 << 1 << 1 << (int)Args.size() << SourceRange(Loc);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
return Actions.ActOnTypeTrait(TypeTraitFromTokKind(Kind), Loc, Args, EndLoc);
|
||||
}
|
||||
|
||||
|
|
|
@ -5427,9 +5427,26 @@ void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
|
|||
}
|
||||
}
|
||||
|
||||
bool Sema::CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N) {
|
||||
if (Arity && N != Arity) {
|
||||
Diag(Loc, diag::err_type_trait_arity)
|
||||
<< Arity << 0 << (Arity > 1) << (int)N << SourceRange(Loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Arity && N == 0) {
|
||||
Diag(Loc, diag::err_type_trait_arity)
|
||||
<< 1 << 1 << 1 << (int)N << SourceRange(Loc);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
|
||||
ArrayRef<TypeSourceInfo *> Args,
|
||||
SourceLocation RParenLoc) {
|
||||
if (!CheckTypeTraitArity(getTypeTraitArity(Kind), KWLoc, Args.size()))
|
||||
return ExprError();
|
||||
QualType ResultType = Context.getLogicalOperationType();
|
||||
|
||||
if (Kind <= UTT_Last && !CheckUnaryTypeTraitTypeCompleteness(
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only %s -verify
|
||||
|
||||
// Shouldn't crash here
|
||||
// Reported by https://github.com/llvm/llvm-project/issues/57008
|
||||
template<class... Ts> bool b = __is_constructible(Ts...); // expected-error{{type trait requires 1 or more arguments}}
|
||||
bool x = b<>; // expected-note{{in instantiation of variable template specialization}}
|
Loading…
Reference in New Issue