diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h --- a/clang/include/clang/AST/DependenceFlags.h +++ b/clang/include/clang/AST/DependenceFlags.h @@ -50,14 +50,16 @@ /// Whether this type is a variably-modified type (C99 6.7.5). VariablyModified = 8, - // FIXME: add Error bit. + /// Whether this type references an error, e.g. decltype(err-expression) + /// yields an error type. + Error = 16, None = 0, - All = 15, + All = 31, DependentInstantiation = Dependent | Instantiation, - LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/VariablyModified) + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Error) }; }; using TypeDependence = TypeDependenceScope::TypeDependence; @@ -147,6 +149,7 @@ return translate(V, UnexpandedPack, TypeDependence::UnexpandedPack) | translate(V, Instantiation, TypeDependence::Instantiation) | translate(V, Dependent, TypeDependence::Dependent) | + translate(V, Error, TypeDependence::Error) | translate(V, VariablyModified, TypeDependence::VariablyModified); } diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2139,6 +2139,11 @@ return static_cast(TypeBits.Dependence); } + /// Whether this type is an error type. + bool containsErrors() const { + return getDependence() & TypeDependence::Error; + } + /// Whether this type is a dependent type, meaning that its definition /// somehow depends on a template parameter (C++ [temp.dep.type]). bool isDependentType() const { diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -3105,10 +3105,14 @@ auto RunSignatureHelp = [&]() { ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); - assert(TypeRep && "invalid types should be handled before"); - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); + QualType PreferredType; + // ActOnTypeName might adjust DeclaratorInfo and return a null type even + // the passing DeclaratorInfo is valid, e.g. running SignatureHelp on + // `new decltype(invalid) (^)`. + if (TypeRep) + PreferredType = Actions.ProduceConstructorSignatureHelp( + getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), + DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); CalledSignatureHelp = true; return PreferredType; }; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1591,6 +1591,8 @@ Result = Context.IntTy; declarator.setInvalidType(true); } + if (Result->containsErrors()) + declarator.setInvalidType(true); break; } case DeclSpec::TST_decltype: { @@ -1602,6 +1604,8 @@ Result = Context.IntTy; declarator.setInvalidType(true); } + if (Result->containsErrors()) + declarator.setInvalidType(true); break; } case DeclSpec::TST_underlyingType: diff --git a/clang/test/AST/ast-dump-expr-errors.cpp b/clang/test/AST/ast-dump-expr-errors.cpp --- a/clang/test/AST/ast-dump-expr-errors.cpp +++ b/clang/test/AST/ast-dump-expr-errors.cpp @@ -42,5 +42,9 @@ // FIXME: store initializer even when 'auto' could not be deduced. // Expressions with errors currently do not keep initializers around. -// CHECK: `-VarDecl {{.*}} invalid e 'auto' +// CHECK: -VarDecl {{.*}} invalid e 'auto' auto e = bar(); + +// Error type should result in an invalid decl. +// CHECK: -VarDecl {{.*}} invalid f 'decltype((bar))' +decltype(bar()) f; diff --git a/clang/test/Sema/invalid-member.cpp b/clang/test/Sema/invalid-member.cpp --- a/clang/test/Sema/invalid-member.cpp +++ b/clang/test/Sema/invalid-member.cpp @@ -1,7 +1,15 @@ // RUN: %clang_cc1 -verify -fsyntax-only %s -void foo(); // expected-note {{requires 0 arguments}} +// RUN: %clang_cc1 -verify -fsyntax-only -frecovery-ast %s + +void foo(); // expected-note 2{{requires 0 arguments}} class X { decltype(foo(42)) invalid; // expected-error {{no matching function}} }; // Should be able to evaluate sizeof without crashing. static_assert(sizeof(X) == 1, "No valid members"); + +class Y { + typeof(foo(42)) invalid; // expected-error {{no matching function}} +}; +// Should be able to evaluate sizeof without crashing. +static_assert(sizeof(Y) == 1, "No valid members");