From: Alexey Bataev Date: Thu, 21 Jan 2016 12:54:48 +0000 (+0000) Subject: Fix crash for typedefs for arrays of runtime bounds in Lambdas/Captured Statements... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8a851046bed598fd4cf3251028781191324c900c;p=clang Fix crash for typedefs for arrays of runtime bounds in Lambdas/Captured Statements, used in sizeof() expression only. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@258396 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index aacbda402f..fc1a9268b1 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3748,6 +3748,128 @@ bool Sema::CheckVecStepExpr(Expr *E) { return CheckUnaryExprOrTypeTraitOperand(E, UETT_VecStep); } +static void captureVariablyModifiedType(ASTContext &Context, QualType T, + CapturingScopeInfo *CSI) { + assert(T->isVariablyModifiedType()); + assert(CSI != nullptr); + + // We're going to walk down into the type and look for VLA expressions. + do { + const Type *Ty = T.getTypePtr(); + switch (Ty->getTypeClass()) { +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + T = QualType(); + break; + // These types are never variably-modified. + case Type::Builtin: + case Type::Complex: + case Type::Vector: + case Type::ExtVector: + case Type::Record: + case Type::Enum: + case Type::Elaborated: + case Type::TemplateSpecialization: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + case Type::Pipe: + llvm_unreachable("type class is never variably-modified!"); + case Type::Adjusted: + T = cast(Ty)->getOriginalType(); + break; + case Type::Decayed: + T = cast(Ty)->getPointeeType(); + break; + case Type::Pointer: + T = cast(Ty)->getPointeeType(); + break; + case Type::BlockPointer: + T = cast(Ty)->getPointeeType(); + break; + case Type::LValueReference: + case Type::RValueReference: + T = cast(Ty)->getPointeeType(); + break; + case Type::MemberPointer: + T = cast(Ty)->getPointeeType(); + break; + case Type::ConstantArray: + case Type::IncompleteArray: + // Losing element qualification here is fine. + T = cast(Ty)->getElementType(); + break; + case Type::VariableArray: { + // Losing element qualification here is fine. + const VariableArrayType *VAT = cast(Ty); + + // Unknown size indication requires no size computation. + // Otherwise, evaluate and record it. + if (auto Size = VAT->getSizeExpr()) { + if (!CSI->isVLATypeCaptured(VAT)) { + RecordDecl *CapRecord = nullptr; + if (auto LSI = dyn_cast(CSI)) { + CapRecord = LSI->Lambda; + } else if (auto CRSI = dyn_cast(CSI)) { + CapRecord = CRSI->TheRecordDecl; + } + if (CapRecord) { + auto ExprLoc = Size->getExprLoc(); + auto SizeType = Context.getSizeType(); + // Build the non-static data member. + auto Field = + FieldDecl::Create(Context, CapRecord, ExprLoc, ExprLoc, + /*Id*/ nullptr, SizeType, /*TInfo*/ nullptr, + /*BW*/ nullptr, /*Mutable*/ false, + /*InitStyle*/ ICIS_NoInit); + Field->setImplicit(true); + Field->setAccess(AS_private); + Field->setCapturedVLAType(VAT); + CapRecord->addDecl(Field); + + CSI->addVLATypeCapture(ExprLoc, SizeType); + } + } + } + T = VAT->getElementType(); + break; + } + case Type::FunctionProto: + case Type::FunctionNoProto: + T = cast(Ty)->getReturnType(); + break; + case Type::Paren: + case Type::TypeOf: + case Type::UnaryTransform: + case Type::Attributed: + case Type::SubstTemplateTypeParm: + case Type::PackExpansion: + // Keep walking after single level desugaring. + T = T.getSingleStepDesugaredType(Context); + break; + case Type::Typedef: + T = cast(Ty)->desugar(); + break; + case Type::Decltype: + T = cast(Ty)->desugar(); + break; + case Type::Auto: + T = cast(Ty)->getDeducedType(); + break; + case Type::TypeOfExpr: + T = cast(Ty)->getUnderlyingExpr()->getType(); + break; + case Type::Atomic: + T = cast(Ty)->getValueType(); + break; + } + } while (!T.isNull() && T->isVariablyModifiedType()); +} + /// \brief Build a sizeof or alignof expression given a type operand. ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, @@ -3763,6 +3885,20 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind)) return ExprError(); + if (T->isVariablyModifiedType() && FunctionScopes.size() > 1) { + if (auto *TT = T->getAs()) { + if (auto *CSI = dyn_cast(FunctionScopes.back())) { + DeclContext *DC = nullptr; + if (auto LSI = dyn_cast(CSI)) + DC = LSI->CallOperator; + else if (auto CRSI = dyn_cast(CSI)) + DC = CRSI->TheCapturedDecl; + if (DC && TT->getDecl()->getDeclContext() != DC) + captureVariablyModifiedType(Context, T, CSI); + } + } + } + // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. return new (Context) UnaryExprOrTypeTraitExpr( ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd()); @@ -13158,120 +13294,7 @@ bool Sema::tryCaptureVariable( QualType QTy = Var->getType(); if (ParmVarDecl *PVD = dyn_cast_or_null(Var)) QTy = PVD->getOriginalType(); - do { - const Type *Ty = QTy.getTypePtr(); - switch (Ty->getTypeClass()) { -#define TYPE(Class, Base) -#define ABSTRACT_TYPE(Class, Base) -#define NON_CANONICAL_TYPE(Class, Base) -#define DEPENDENT_TYPE(Class, Base) case Type::Class: -#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" - QTy = QualType(); - break; - // These types are never variably-modified. - case Type::Builtin: - case Type::Complex: - case Type::Vector: - case Type::ExtVector: - case Type::Record: - case Type::Enum: - case Type::Elaborated: - case Type::TemplateSpecialization: - case Type::ObjCObject: - case Type::ObjCInterface: - case Type::ObjCObjectPointer: - case Type::Pipe: - llvm_unreachable("type class is never variably-modified!"); - case Type::Adjusted: - QTy = cast(Ty)->getOriginalType(); - break; - case Type::Decayed: - QTy = cast(Ty)->getPointeeType(); - break; - case Type::Pointer: - QTy = cast(Ty)->getPointeeType(); - break; - case Type::BlockPointer: - QTy = cast(Ty)->getPointeeType(); - break; - case Type::LValueReference: - case Type::RValueReference: - QTy = cast(Ty)->getPointeeType(); - break; - case Type::MemberPointer: - QTy = cast(Ty)->getPointeeType(); - break; - case Type::ConstantArray: - case Type::IncompleteArray: - // Losing element qualification here is fine. - QTy = cast(Ty)->getElementType(); - break; - case Type::VariableArray: { - // Losing element qualification here is fine. - const VariableArrayType *VAT = cast(Ty); - - // Unknown size indication requires no size computation. - // Otherwise, evaluate and record it. - if (auto Size = VAT->getSizeExpr()) { - if (!CSI->isVLATypeCaptured(VAT)) { - RecordDecl *CapRecord = nullptr; - if (auto LSI = dyn_cast(CSI)) { - CapRecord = LSI->Lambda; - } else if (auto CRSI = dyn_cast(CSI)) { - CapRecord = CRSI->TheRecordDecl; - } - if (CapRecord) { - auto ExprLoc = Size->getExprLoc(); - auto SizeType = Context.getSizeType(); - // Build the non-static data member. - auto Field = FieldDecl::Create( - Context, CapRecord, ExprLoc, ExprLoc, - /*Id*/ nullptr, SizeType, /*TInfo*/ nullptr, - /*BW*/ nullptr, /*Mutable*/ false, - /*InitStyle*/ ICIS_NoInit); - Field->setImplicit(true); - Field->setAccess(AS_private); - Field->setCapturedVLAType(VAT); - CapRecord->addDecl(Field); - - CSI->addVLATypeCapture(ExprLoc, SizeType); - } - } - } - QTy = VAT->getElementType(); - break; - } - case Type::FunctionProto: - case Type::FunctionNoProto: - QTy = cast(Ty)->getReturnType(); - break; - case Type::Paren: - case Type::TypeOf: - case Type::UnaryTransform: - case Type::Attributed: - case Type::SubstTemplateTypeParm: - case Type::PackExpansion: - // Keep walking after single level desugaring. - QTy = QTy.getSingleStepDesugaredType(getASTContext()); - break; - case Type::Typedef: - QTy = cast(Ty)->desugar(); - break; - case Type::Decltype: - QTy = cast(Ty)->desugar(); - break; - case Type::Auto: - QTy = cast(Ty)->getDeducedType(); - break; - case Type::TypeOfExpr: - QTy = cast(Ty)->getUnderlyingExpr()->getType(); - break; - case Type::Atomic: - QTy = cast(Ty)->getValueType(); - break; - } - } while (!QTy.isNull() && QTy->isVariablyModifiedType()); + captureVariablyModifiedType(Context, QTy, CSI); } if (getLangOpts().OpenMP) { diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp index 2ea0561f9e..4df44f4c5f 100644 --- a/test/CodeGenCXX/lambda-expressions.cpp +++ b/test/CodeGenCXX/lambda-expressions.cpp @@ -10,10 +10,23 @@ void *use = &used; // CHECK: @cvar = global extern "C" auto cvar = []{}; +// CHECK-LABEL: define i32 @_Z9ARBSizeOfi(i32 +int ARBSizeOf(int n) { + typedef double (T)[8][n]; + using TT = double [8][n]; + return [&]() -> int { + typedef double(T1)[8][n]; + using TT1 = double[8][n]; + return sizeof(T) + sizeof(T1) + sizeof(TT) + sizeof(TT1); + }(); +} + +// CHECK-LABEL: define internal i32 @"_ZZ9ARBSizeOfiENK3$_0clEv" + int a() { return []{ return 1; }(); } // CHECK-LABEL: define i32 @_Z1av -// CHECK: call i32 @"_ZZ1avENK3$_0clEv" -// CHECK-LABEL: define internal i32 @"_ZZ1avENK3$_0clEv" +// CHECK: call i32 @"_ZZ1avENK3$_1clEv" +// CHECK-LABEL: define internal i32 @"_ZZ1avENK3$_1clEv" // CHECK: ret i32 1 int b(int x) { return [x]{return x;}(); } @@ -21,8 +34,8 @@ int b(int x) { return [x]{return x;}(); } // CHECK: store i32 // CHECK: load i32, i32* // CHECK: store i32 -// CHECK: call i32 @"_ZZ1biENK3$_1clEv" -// CHECK-LABEL: define internal i32 @"_ZZ1biENK3$_1clEv" +// CHECK: call i32 @"_ZZ1biENK3$_2clEv" +// CHECK-LABEL: define internal i32 @"_ZZ1biENK3$_2clEv" // CHECK: load i32, i32* // CHECK: ret i32 @@ -30,8 +43,8 @@ int c(int x) { return [&x]{return x;}(); } // CHECK-LABEL: define i32 @_Z1ci // CHECK: store i32 // CHECK: store i32* -// CHECK: call i32 @"_ZZ1ciENK3$_2clEv" -// CHECK-LABEL: define internal i32 @"_ZZ1ciENK3$_2clEv" +// CHECK: call i32 @"_ZZ1ciENK3$_3clEv" +// CHECK-LABEL: define internal i32 @"_ZZ1ciENK3$_3clEv" // CHECK: load i32*, i32** // CHECK: load i32, i32* // CHECK: ret i32 @@ -43,8 +56,8 @@ int d(int x) { D y[10]; [x,y] { return y[x].x; }(); } // CHECK: call void @_ZN1DC1Ev // CHECK: icmp ult i64 %{{.*}}, 10 // CHECK: call void @_ZN1DC1ERKS_ -// CHECK: call i32 @"_ZZ1diENK3$_3clEv" -// CHECK-LABEL: define internal i32 @"_ZZ1diENK3$_3clEv" +// CHECK: call i32 @"_ZZ1diENK3$_4clEv" +// CHECK-LABEL: define internal i32 @"_ZZ1diENK3$_4clEv" // CHECK: load i32, i32* // CHECK: load i32, i32* // CHECK: ret i32 @@ -54,18 +67,18 @@ int e(E a, E b, bool cond) { [a,b,cond](){ return (cond ? a : b).x; }(); } // CHECK-LABEL: define i32 @_Z1e1ES_b // CHECK: call void @_ZN1EC1ERKS_ // CHECK: invoke void @_ZN1EC1ERKS_ -// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_4clEv" -// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev" -// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev" +// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_5clEv" +// CHECK: call void @"_ZZ1e1ES_bEN3$_5D1Ev" +// CHECK: call void @"_ZZ1e1ES_bEN3$_5D1Ev" -// CHECK-LABEL: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv" +// CHECK-LABEL: define internal i32 @"_ZZ1e1ES_bENK3$_5clEv" // CHECK: trunc i8 // CHECK: load i32, i32* // CHECK: ret i32 void f() { // CHECK-LABEL: define void @_Z1fv() - // CHECK: @"_ZZ1fvENK3$_5cvPFiiiEEv" + // CHECK: @"_ZZ1fvENK3$_6cvPFiiiEEv" // CHECK-NEXT: store i32 (i32, i32)* // CHECK-NEXT: ret void int (*fp)(int, int) = [](int x, int y){ return x + y; }; @@ -74,7 +87,7 @@ void f() { static int k; int g() { int &r = k; - // CHECK-LABEL: define internal i32 @"_ZZ1gvENK3$_6clEv"( + // CHECK-LABEL: define internal i32 @"_ZZ1gvENK3$_7clEv"( // CHECK-NOT: } // CHECK: load i32, i32* @_ZL1k, return [] { return r; } (); @@ -91,7 +104,7 @@ void staticarrayref(){ }(); } -// CHECK-LABEL: define internal i32* @"_ZZ11PR22071_funvENK3$_8clEv" +// CHECK-LABEL: define internal i32* @"_ZZ11PR22071_funvENK3$_9clEv" // CHECK: ret i32* @PR22071_var int PR22071_var; int *PR22071_fun() { @@ -99,19 +112,19 @@ int *PR22071_fun() { return [&] { return &y; }(); } -// CHECK-LABEL: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev" +// CHECK-LABEL: define internal void @"_ZZ1e1ES_bEN3$_5D2Ev" -// CHECK-LABEL: define internal i32 @"_ZZ1fvEN3$_58__invokeEii" +// CHECK-LABEL: define internal i32 @"_ZZ1fvEN3$_68__invokeEii" // CHECK: store i32 // CHECK-NEXT: store i32 // CHECK-NEXT: load i32, i32* // CHECK-NEXT: load i32, i32* -// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_5clEii" +// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_6clEii" // CHECK-NEXT: ret i32 -// CHECK-LABEL: define internal void @"_ZZ1hvEN3$_98__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} { +// CHECK-LABEL: define internal void @"_ZZ1hvEN4$_108__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} { // CHECK-NOT: = -// CHECK: call void @"_ZZ1hvENK3$_9clEv"(%struct.A* sret %agg.result, +// CHECK: call void @"_ZZ1hvENK4$_10clEv"(%struct.A* sret %agg.result, // CHECK-NEXT: ret void struct A { ~A(); }; void h() {