Skip to content

Rough first stab at addressing #85120 #85147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Change the result type of a function type once it is deduced.
void adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType);

/// Transform a function type to have the provided result type, preserving
/// AttributedType and MacroQualifiedType sugar.
QualType getFunctionTypeWithResultType(QualType OrigFuncType, QualType ResultType,
const FunctionProtoType::ExtProtoInfo &EPI) const;

/// Get a function type and produce the equivalent function type with the
/// specified exception specification. Type sugar that can be present on a
/// declaration of a function with an exception specification is permitted
Expand Down
62 changes: 60 additions & 2 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3140,13 +3140,71 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
return cast<FunctionType>(Result.getTypePtr());
}

// EPI is provided by the caller because in the case of adjustDeducedFunctionResultType, it
// is copied entirely from the previous FunctionType, but with a block (ActOnBlockStmtExpr),
// it is more complicated...
QualType ASTContext::getFunctionTypeWithResultType(QualType OrigFuncType, QualType ResultType,
const FunctionProtoType::ExtProtoInfo &EPI) const
{
// Might be wrapped in a macro qualified type.
if (const auto *MQT = dyn_cast<MacroQualifiedType>(OrigFuncType)) {
return getMacroQualifiedType(
getFunctionTypeWithResultType(MQT->getUnderlyingType(), ResultType, EPI),
MQT->getMacroIdentifier());
}

// Might have a calling-convention attribute.
if (const auto *AT = dyn_cast<AttributedType>(OrigFuncType)) {
return getAttributedType(
AT->getAttrKind(),
getFunctionTypeWithResultType(AT->getModifiedType(), ResultType, EPI),
getFunctionTypeWithResultType(AT->getEquivalentType(), ResultType, EPI));
}

// Anything else must be a function type. Rebuild it with the new return value.
const auto *FPT = OrigFuncType->castAs<FunctionProtoType>();
return getFunctionType(ResultType, FPT->getParamTypes(), EPI);
}

#if 0
static void examineType(const char* prefix, QualType QT, const char* term)
{
llvm::outs() << prefix;
if (const auto *MQT = dyn_cast<MacroQualifiedType>(QT)) {
examineType( "MacroQualifiedType <", MQT->getUnderlyingType(), ">");
} else if (const auto *AT = dyn_cast<AttributedType>(QT)) {
examineType("AttributedType <", AT->getEquivalentType(), ">");
} else {
const auto *FPT = QT->castAs<FunctionProtoType>();
assert(FPT);
llvm::outs() << QT;
}
llvm::outs() << term;
}
#endif

void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
QualType ResultType) {
FD = FD->getMostRecentDecl();
while (true) {
const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
QualType OrigFuncType = FD->getType();
const auto *FPT = OrigFuncType->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
FD->setType(getFunctionType(ResultType, FPT->getParamTypes(), EPI));
#if 1 // my new way
QualType NewFuncType = getFunctionTypeWithResultType(OrigFuncType, ResultType, EPI);
#else // original way
QualType NewFuncType = getFunctionType(ResultType, FPT->getParamTypes(), EPI);
#endif
/*llvm::outs() << "transform " << OrigFuncType << " -> " << NewFuncType << "\n";
llvm::outs() << " isConstQualified " << OrigFuncType.isConstQualified() << NewFuncType.isConstQualified() << "\n";
llvm::outs() << " isLocalConstQualified " << OrigFuncType.isLocalConstQualified() << NewFuncType.isLocalConstQualified() << "\n";
llvm::outs() << " const method " << FPT->isConst() << NewFuncType->castAs<FunctionProtoType>()->isConst() << "\n";
llvm::outs() << " canonical " << NewFuncType.getCanonicalType() << "\n";*/

/*examineType("original ", OrigFuncType, "\n");
examineType("deduced ", NewFuncType, "\n");*/

FD->setType(NewFuncType);
if (FunctionDecl *Next = FD->getPreviousDecl())
FD = Next;
else
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17161,7 +17161,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals = Qualifiers();
EPI.ExtInfo = Ext;
BlockTy = Context.getFunctionType(RetTy, FPT->getParamTypes(), EPI);
BlockTy = Context.getFunctionTypeWithResultType(BSI->FunctionType, RetTy, EPI);
}

// If we don't have a function type, just build one from nothing.
Expand Down
61 changes: 59 additions & 2 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -13830,6 +13830,33 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getSema().AddTemplateParametersToLambdaCallOperator(NewCallOperator, Class,
TPL);

#if 0
// Conflicting old bug fix attempt

@@ -13719,10 +13719,23 @@
// it introduces a mapping of the original to the newly created
// transformed parameters.
TypeSourceInfo *NewCallOpTSI = nullptr;
+ // <rdar://117704214> Crash involving AttributedTypeLoc on lambda.
+ // Hack of a fix adapted from https://github.com/llvm/llvm-project/issues/58366
+ FunctionProtoTypeLoc NewCallOpFPTL;
{
TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
auto OldCallOpFPTL =
OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+ AttributedTypeLoc OldCallOpATTL;
+ bool IsAttributed = false;
+ if (!OldCallOpFPTL) {
+ OldCallOpATTL = OldCallOpTSI->getTypeLoc().getAs<AttributedTypeLoc>();
+ assert(OldCallOpATTL);
+ OldCallOpFPTL =
+ OldCallOpATTL.getModifiedLoc().getAs<FunctionProtoTypeLoc>();
+ assert(OldCallOpFPTL);
+ IsAttributed = true;
+ }
#endif


// Transform the type of the original lambda's call operator.
// The transformation MUST be done in the CurrentInstantiationScope since
// it introduces a mapping of the original to the newly created
Expand Down Expand Up @@ -13867,8 +13894,38 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {

if (NewCallOpType.isNull())
return ExprError();
NewCallOpTSI =
NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);

// NewCallOpTSI =
// NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
if (IsAttributed) {
const AttributedType *oldType = OldCallOpATTL.getTypePtr();

const Attr *newAttr = getDerived().TransformAttr(OldCallOpATTL.getAttr());
if (!newAttr)
return ExprError();

QualType equivalentType =
getDerived().TransformType(oldType->getEquivalentType());
if (equivalentType.isNull())
return ExprError();
QualType result = SemaRef.Context.getAttributedType(
OldCallOpATTL.getAttrKind(), NewCallOpType, equivalentType);

AttributedTypeLoc newTL =
NewCallOpTLBuilder.push<AttributedTypeLoc>(result);
newTL.setAttr(newAttr);

NewCallOpTSI =
NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, result);
NewCallOpFPTL = NewCallOpTSI->getTypeLoc()
.castAs<AttributedTypeLoc>()
.getModifiedLoc()
.castAs<FunctionProtoTypeLoc>();
} else {
NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context,
NewCallOpType);
NewCallOpFPTL = NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
}
}

ArrayRef<ParmVarDecl *> Params;
Expand Down