diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -737,7 +737,7 @@ def Annotate : InheritableParamAttr { let Spellings = [Clang<"annotate">]; - let Args = [StringArgument<"Annotation">]; + let Args = [StringArgument<"Annotation">, VariadicExprArgument<"Args">]; // Ensure that the annotate attribute can be used with // '#pragma clang attribute' even though it has no subject list. let PragmaAttributeSupport = 1; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2857,7 +2857,7 @@ "%0 attribute cannot be applied to sizeless type %1">; def err_attribute_argument_n_type : Error< "%0 attribute requires parameter %1 to be %select{int or bool|an integer " - "constant|a string|an identifier}2">; + "constant|a string|an identifier|a constant expression}2">; def err_attribute_argument_type : Error< "%0 attribute requires %select{int or bool|an integer " "constant|a string|an identifier}1">; diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -1023,7 +1023,8 @@ AANT_ArgumentIntOrBool, AANT_ArgumentIntegerConstant, AANT_ArgumentString, - AANT_ArgumentIdentifier + AANT_ArgumentIdentifier, + AANT_ArgumentConstantExpr, }; /// These constants match the enumerated choices of @@ -1072,6 +1073,31 @@ return PD; } +/// AttributeCommonInfo has a non-explicit constructor which takes an +/// SourceRange as its only argument, this constructor has many uses so making +/// it explicit is hard. This constructor causes ambiguity with +/// DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, SourceRange R). +/// We use SFINAE to disable any conversion and remove any ambiguity. +template ::value, int> = 0> +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const ACI &CI) { + DB.AddTaggedVal(reinterpret_cast(CI.getAttrName()), + DiagnosticsEngine::ak_identifierinfo); + return DB; +} + +template ::value, int> = 0> +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const ACI &CI) { + PD.AddTaggedVal(reinterpret_cast(CI.getAttrName()), + DiagnosticsEngine::ak_identifierinfo); + return PD; +} + } // namespace clang #endif // LLVM_CLANG_SEMA_ATTRIBUTELIST_H diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9851,6 +9851,10 @@ /// declaration. void AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E); + /// AddAnnotationAttr - Adds an annotation Annot with Args arguments to D. + void AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef Annot, MutableArrayRef Args); + /// AddLaunchBoundsAttr - Adds a launch_bounds attribute to a particular /// declaration. void AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3396,7 +3396,8 @@ // non-wide string literal, potentially casted, so the cast<> is safe. const Expr *AnnotationStrExpr = E->getArg(1)->IgnoreParenCasts(); StringRef Str = cast(AnnotationStrExpr)->getString(); - return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc())); + return RValue::get( + EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc(), nullptr)); } case Builtin::BI__builtin_addcb: case Builtin::BI__builtin_addcs: diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4319,7 +4319,8 @@ llvm::Value *EmitAnnotationCall(llvm::Function *AnnotationFn, llvm::Value *AnnotatedVal, StringRef AnnotationStr, - SourceLocation Location); + SourceLocation Location, + const AnnotateAttr *Attr); /// Emit local annotations for the local variable V, declared by D. void EmitVarAnnotations(const VarDecl *D, llvm::Value *V); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2254,13 +2254,16 @@ llvm::Value *CodeGenFunction::EmitAnnotationCall(llvm::Function *AnnotationFn, llvm::Value *AnnotatedVal, StringRef AnnotationStr, - SourceLocation Location) { - llvm::Value *Args[4] = { - AnnotatedVal, - Builder.CreateBitCast(CGM.EmitAnnotationString(AnnotationStr), Int8PtrTy), - Builder.CreateBitCast(CGM.EmitAnnotationUnit(Location), Int8PtrTy), - CGM.EmitAnnotationLineNo(Location) + SourceLocation Location, + const AnnotateAttr *Attr) { + SmallVector Args = { + AnnotatedVal, + Builder.CreateBitCast(CGM.EmitAnnotationString(AnnotationStr), Int8PtrTy), + Builder.CreateBitCast(CGM.EmitAnnotationUnit(Location), Int8PtrTy), + CGM.EmitAnnotationLineNo(Location), }; + if (Attr) + Args.push_back(CGM.EmitAnnotationArgs(Attr)); return Builder.CreateCall(AnnotationFn, Args); } @@ -2271,7 +2274,7 @@ for (const auto *I : D->specific_attrs()) EmitAnnotationCall(CGM.getIntrinsic(llvm::Intrinsic::var_annotation), Builder.CreateBitCast(V, CGM.Int8PtrTy, V->getName()), - I->getAnnotation(), D->getLocation()); + I->getAnnotation(), D->getLocation(), I); } Address CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D, @@ -2288,7 +2291,7 @@ // itself. if (VTy != CGM.Int8PtrTy) V = Builder.CreateBitCast(V, CGM.Int8PtrTy); - V = EmitAnnotationCall(F, V, I->getAnnotation(), D->getLocation()); + V = EmitAnnotationCall(F, V, I->getAnnotation(), D->getLocation(), I); V = Builder.CreateBitCast(V, VTy); } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -413,6 +413,9 @@ /// Map used to get unique annotation strings. llvm::StringMap AnnotationStrings; + /// Used for uniquing of annotation arguments. + llvm::DenseMap AnnotationArgs; + llvm::StringMap CFConstantStringMap; llvm::DenseMap ConstantStringMap; @@ -1233,6 +1236,9 @@ /// Emit the annotation line number. llvm::Constant *EmitAnnotationLineNo(SourceLocation L); + /// Emit additional args of the annotation. + llvm::Constant *EmitAnnotationArgs(const AnnotateAttr *Attr); + /// Generate the llvm::ConstantStruct which contains the annotation /// information for a given GlobalValue. The annotation struct is /// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2332,13 +2332,48 @@ return llvm::ConstantInt::get(Int32Ty, LineNo); } +llvm::Constant *CodeGenModule::EmitAnnotationArgs(const AnnotateAttr *Attr) { + ArrayRef Exprs = {Attr->args_begin(), Attr->args_size()}; + Exprs = Exprs.drop_front(); + if (Exprs.empty()) + return llvm::ConstantPointerNull::get(Int8PtrTy); + + llvm::FoldingSetNodeID ID; + for (Expr *E : Exprs) { + ID.Add(cast(E)->getAPValueResult()); + } + llvm::Constant *&Lookup = AnnotationArgs[ID.ComputeHash()]; + if (Lookup) + return Lookup; + + llvm::SmallVector LLVMArgs; + LLVMArgs.reserve(Exprs.size()); + ConstantEmitter ConstEmiter(*this); + llvm::transform(Exprs, std::back_inserter(LLVMArgs), [&](const Expr *E) { + const auto *CE = cast(E); + return ConstEmiter.emitAbstract(CE->getBeginLoc(), CE->getAPValueResult(), + CE->getType()); + }); + auto *Struct = llvm::ConstantStruct::getAnon(LLVMArgs); + auto *GV = new llvm::GlobalVariable(getModule(), Struct->getType(), true, + llvm::GlobalValue::PrivateLinkage, Struct, + ".args"); + GV->setSection(AnnotationSection); + GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + auto *Bitcasted = llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + + Lookup = Bitcasted; + return Bitcasted; +} + llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV, const AnnotateAttr *AA, SourceLocation L) { // Get the globals for file name, annotation, and the line number. llvm::Constant *AnnoGV = EmitAnnotationString(AA->getAnnotation()), *UnitGV = EmitAnnotationUnit(L), - *LineNoCst = EmitAnnotationLineNo(L); + *LineNoCst = EmitAnnotationLineNo(L), + *Args = EmitAnnotationArgs(AA); llvm::Constant *ASZeroGV = GV; if (GV->getAddressSpace() != 0) { @@ -2347,11 +2382,12 @@ } // Create the ConstantStruct for the global annotation. - llvm::Constant *Fields[4] = { - llvm::ConstantExpr::getBitCast(ASZeroGV, Int8PtrTy), - llvm::ConstantExpr::getBitCast(AnnoGV, Int8PtrTy), - llvm::ConstantExpr::getBitCast(UnitGV, Int8PtrTy), - LineNoCst + llvm::Constant *Fields[] = { + llvm::ConstantExpr::getBitCast(ASZeroGV, Int8PtrTy), + llvm::ConstantExpr::getBitCast(AnnoGV, Int8PtrTy), + llvm::ConstantExpr::getBitCast(UnitGV, Int8PtrTy), + LineNoCst, + Args, }; return llvm::ConstantStruct::getAnon(Fields); } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3682,20 +3682,65 @@ RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL)); } +void Sema::AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef Str, MutableArrayRef Args) { + auto *Attr = AnnotateAttr::Create(Context, Str, Args.data(), Args.size(), CI); + llvm::SmallVector Notes; + for (unsigned Idx = 1; Idx < Attr->args_size(); Idx++) { + Expr *&E = Attr->args_begin()[Idx]; + assert(E && "error are handled before"); + if (E->isValueDependent() || E->isTypeDependent()) + continue; + + if (E->getType()->isArrayType()) + E = ImpCastExprToType(E, Context.getPointerType(E->getType()), + clang::CK_ArrayToPointerDecay) + .get(); + if (E->getType()->isFunctionType()) + E = ImplicitCastExpr::Create(Context, + Context.getPointerType(E->getType()), + clang::CK_FunctionToPointerDecay, E, nullptr, + VK_RValue, FPOptionsOverride()); + if (E->isLValue()) + E = ImplicitCastExpr::Create(Context, E->getType().getNonReferenceType(), + clang::CK_LValueToRValue, E, nullptr, + VK_RValue, FPOptionsOverride()); + + Expr::EvalResult Eval; + Notes.clear(); + Eval.Diag = &Notes; + + bool Result = + E->EvaluateAsConstantExpr(Eval, Expr::EvaluateForCodeGen, Context); + + if (!Result || !Notes.empty()) { + Diag(E->getBeginLoc(), diag::err_attribute_argument_n_type) + << CI << Idx << AANT_ArgumentConstantExpr; + for (auto &Note : Notes) + Diag(Note.first, Note.second); + return; + } + assert(Eval.Val.hasValue()); + E = ConstantExpr::Create(Context, E, Eval.Val); + } + D->addAttr(Attr); +} + static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // Make sure that there is a string literal as the annotation's single + // Make sure that there is a string literal as the annotation's first // argument. StringRef Str; if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; - // Don't duplicate annotations that are already set. - for (const auto *I : D->specific_attrs()) { - if (I->getAnnotation() == Str) - return; + llvm::SmallVector Args; + Args.reserve(AL.getNumArgs()); + for (unsigned Idx = 0; Idx < AL.getNumArgs(); Idx++) { + assert(!AL.isArgIdent(Idx)); + Args.push_back(AL.getArgAsExpr(Idx)); } - D->addAttr(::new (S.Context) AnnotateAttr(S.Context, AL, Str)); + S.AddAnnotationAttr(D, AL, Str, Args); } static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -181,6 +181,22 @@ S.AddAllocAlignAttr(New, *Align, Param); } +static void instantiateDependentAnnotationAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const AnnotateAttr *Attr, Decl *New) { + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + SmallVector Args; + Args.reserve(Attr->args_size()); + for (auto *E : Attr->args()) { + ExprResult Result = S.SubstExpr(E, TemplateArgs); + if (!Result.isUsable()) + return; + Args.push_back(Result.get()); + } + S.AddAnnotationAttr(New, *Attr, Attr->getAnnotation(), Args); +} + static Expr *instantiateDependentFunctionAttrCondition( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const Attr *A, Expr *OldCond, const Decl *Tmpl, FunctionDecl *New) { @@ -593,6 +609,10 @@ continue; } + if (const auto *Annotate = dyn_cast(TmplAttr)) { + instantiateDependentAnnotationAttr(*this, TemplateArgs, Annotate, New); + continue; + } if (const auto *EnableIf = dyn_cast(TmplAttr)) { instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl, diff --git a/clang/test/AST/ast-dump-attr.cpp b/clang/test/AST/ast-dump-attr.cpp --- a/clang/test/AST/ast-dump-attr.cpp +++ b/clang/test/AST/ast-dump-attr.cpp @@ -252,10 +252,12 @@ // CHECK-NEXT: DeprecatedAttr{{.*}} Inherited // CHECK-NEXT: WarnUnusedResultAttr{{.*}} Inherited // CHECK-NEXT: AnnotateAttr{{.*}} +// CHECK-NEXT: StringLiteral // CHECK: FunctionDecl{{.*}} mergeAttrTest // CHECK-NEXT: DeprecatedAttr{{.*}} Inherited // CHECK-NEXT: WarnUnusedResultAttr{{.*}} Inherited // CHECK-NEXT: AnnotateAttr{{.*}} Inherited +// CHECK-NEXT: StringLiteral // CHECK-NEXT: UnusedAttr // CHECK-NEXT: NoThreadSafetyAnalysisAttr diff --git a/clang/test/CodeGen/annotations-field.c b/clang/test/CodeGen/annotations-field.c --- a/clang/test/CodeGen/annotations-field.c +++ b/clang/test/CodeGen/annotations-field.c @@ -15,12 +15,12 @@ f.v = argc; // CHECK: getelementptr inbounds %struct.foo, %struct.foo* %f, i32 0, i32 0 // CHECK-NEXT: bitcast i32* {{.*}} to i8* -// CHECK-NEXT: call i8* @llvm.ptr.annotation.p0i8({{.*}}str{{.*}}str{{.*}}i32 8) +// CHECK-NEXT: call i8* @llvm.ptr.annotation.p0i8({{.*}}str{{.*}}str{{.*}}i32 8, i8* null) // CHECK-NEXT: bitcast i8* {{.*}} to i32* // CHECK-NEXT: bitcast i32* {{.*}} to i8* -// CHECK-NEXT: call i8* @llvm.ptr.annotation.p0i8({{.*}}str{{.*}}str{{.*}}i32 8) +// CHECK-NEXT: call i8* @llvm.ptr.annotation.p0i8({{.*}}str{{.*}}str{{.*}}i32 8, i8* null) // CHECK-NEXT: bitcast i8* {{.*}} to i32* gf.v = argc; -// CHECK: call i8* @llvm.ptr.annotation.p0i8(i8* bitcast (%struct.foo* @gf to i8*), {{.*}}str{{.*}}str{{.*}}i32 8) +// CHECK: call i8* @llvm.ptr.annotation.p0i8(i8* bitcast (%struct.foo* @gf to i8*), {{.*}}str{{.*}}str{{.*}}i32 8, i8* null) return 0; } diff --git a/clang/test/CodeGen/annotations-global.c b/clang/test/CodeGen/annotations-global.c --- a/clang/test/CodeGen/annotations-global.c +++ b/clang/test/CodeGen/annotations-global.c @@ -21,13 +21,13 @@ // FOOS: private unnamed_addr constant [7 x i8] c"sfoo_{{.}}\00", section "llvm.metadata" // FOOS: private unnamed_addr constant [7 x i8] c"sfoo_{{.}}\00", section "llvm.metadata" // FOOS-NOT: sfoo_ -// FOOS: @llvm.global.annotations = appending global [11 x { i8*, i8*, i8*, i32 }] {{.*}}i8* @sfoo{{.*}}i8* @sfoo{{.*}}, section "llvm.metadata" +// FOOS: @llvm.global.annotations = appending global [11 x { i8*, i8*, i8*, i32, i8* }] {{.*}}i8* @sfoo{{.*}}i8* @sfoo{{.*}}, section "llvm.metadata" // FOO: target triple // FOO: private unnamed_addr constant [6 x i8] c"foo_{{.}}\00", section "llvm.metadata" // FOO: private unnamed_addr constant [6 x i8] c"foo_{{.}}\00", section "llvm.metadata" // FOO-NOT: foo_ -// FOO: @llvm.global.annotations = appending global [11 x { i8*, i8*, i8*, i32 }] {{.*}}i8* @foo{{.*}}i8* @foo{{.*}}, section "llvm.metadata" +// FOO: @llvm.global.annotations = appending global [11 x { i8*, i8*, i8*, i32, i8* }] {{.*}}i8* @foo{{.*}}i8* @foo{{.*}}, section "llvm.metadata" // A: target triple // A: private unnamed_addr constant [8 x i8] c"ann_a_{{.}}\00", section "llvm.metadata" @@ -35,13 +35,13 @@ // A: private unnamed_addr constant [8 x i8] c"ann_a_{{.}}\00", section "llvm.metadata" // A: private unnamed_addr constant [8 x i8] c"ann_a_{{.}}\00", section "llvm.metadata" // A-NOT: ann_a_ -// A: @llvm.global.annotations = appending global [11 x { i8*, i8*, i8*, i32 }] {{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}, section "llvm.metadata" +// A: @llvm.global.annotations = appending global [11 x { i8*, i8*, i8*, i32, i8* }] {{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}, section "llvm.metadata" // BAR: target triple // BAR: private unnamed_addr constant [6 x i8] c"bar_{{.}}\00", section "llvm.metadata" // BAR: private unnamed_addr constant [6 x i8] c"bar_{{.}}\00", section "llvm.metadata" // BAR-NOT: bar_ -// BAR: @llvm.global.annotations = appending global [11 x { i8*, i8*, i8*, i32 }] {{.*}}i8* @a.bar{{.*}}i8* @a.bar{{.*}}, section "llvm.metadata" +// BAR: @llvm.global.annotations = appending global [11 x { i8*, i8*, i8*, i32, i8* }] {{.*}}i8* @a.bar{{.*}}i8* @a.bar{{.*}}, section "llvm.metadata" // ADDRSPACE: target triple // ADDRSPACE: @llvm.global.annotations = appending global {{.*}} addrspacecast (i8 addrspace(1)* @addrspace1_var to i8*), {{.*}} diff --git a/clang/test/CodeGen/annotations-loc.c b/clang/test/CodeGen/annotations-loc.c --- a/clang/test/CodeGen/annotations-loc.c +++ b/clang/test/CodeGen/annotations-loc.c @@ -7,4 +7,4 @@ int __attribute((annotate("foo"))) foo(void) { return 0; } // CHECK: private unnamed_addr constant [4 x i8] c"t.c\00" -// CHECK: @llvm.global.annotations = {{.*}}, i32 1 } +// CHECK: @llvm.global.annotations = {{.*}}, i32 1, i8* null } diff --git a/clang/test/CodeGen/annotations-var.c b/clang/test/CodeGen/annotations-var.c --- a/clang/test/CodeGen/annotations-var.c +++ b/clang/test/CodeGen/annotations-var.c @@ -34,9 +34,9 @@ // LOCAL-LABEL: define void @local() // LOCAL: [[LOCALVAR:%.*]] = alloca i32, // LOCAL-NEXT: [[T0:%.*]] = bitcast i32* [[LOCALVAR]] to i8* -// LOCAL-NEXT: call void @llvm.var.annotation(i8* [[T0]], i8* getelementptr inbounds ([15 x i8], [15 x i8]* @{{.*}}), i8* getelementptr inbounds ({{.*}}), i32 33) +// LOCAL-NEXT: call void @llvm.var.annotation(i8* [[T0]], i8* getelementptr inbounds ([15 x i8], [15 x i8]* @{{.*}}), i8* getelementptr inbounds ({{.*}}), i32 33, i8* null) // LOCAL-NEXT: [[T0:%.*]] = bitcast i32* [[LOCALVAR]] to i8* -// LOCAL-NEXT: call void @llvm.var.annotation(i8* [[T0]], i8* getelementptr inbounds ([15 x i8], [15 x i8]* @{{.*}}), i8* getelementptr inbounds ({{.*}}), i32 33) +// LOCAL-NEXT: call void @llvm.var.annotation(i8* [[T0]], i8* getelementptr inbounds ([15 x i8], [15 x i8]* @{{.*}}), i8* getelementptr inbounds ({{.*}}), i32 33, i8* null) } void local_after_return(void) { @@ -53,5 +53,5 @@ // UNDEF-LABEL: define void @undef() // UNDEF: [[UNDEFVAR:%.*]] = alloca i32, // UNDEF-NEXT: [[T0:%.*]] = bitcast i32* [[UNDEFVAR]] to i8* -// UNDEF-NEXT: call void @llvm.var.annotation(i8* [[T0]], i8* getelementptr inbounds ([15 x i8], [15 x i8]* @{{.*}}), i8* getelementptr inbounds ({{.*}}), i32 52) +// UNDEF-NEXT: call void @llvm.var.annotation(i8* [[T0]], i8* getelementptr inbounds ([15 x i8], [15 x i8]* @{{.*}}), i8* getelementptr inbounds ({{.*}}), i32 52, i8* null) } diff --git a/clang/test/CodeGenCXX/attr-annotate.cpp b/clang/test/CodeGenCXX/attr-annotate.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-annotate.cpp @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 %s -S -emit-llvm -triple x86_64-unknown-linux-gnu -o - | FileCheck %s + +//CHECK: @[[STR1:.*]] = private unnamed_addr constant [{{.*}} x i8] c"{{.*}}attr-annotate.cpp\00", section "llvm.metadata" +//CHECK: @[[STR2:.*]] = private unnamed_addr constant [4 x i8] c"abc\00", align 1 +//CHECK: @[[STR:.*]] = private unnamed_addr constant [5 x i8] c"test\00", section "llvm.metadata" +//CHECK: @[[ARGS:.*]] = private unnamed_addr constant { i32, i8*, i32 } { i32 9, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR2:.*]], i32 0, i32 0), i32 8 }, section "llvm.metadata" +//CHECK: @[[ARGS2:.*]] = private unnamed_addr constant { %struct.Struct } { %struct.Struct { i32* getelementptr inbounds ([2 x i32], [2 x i32]* @_ZN1AIjLj9EE2SVE, i32 0, i32 0), i32* bitcast (i8* getelementptr (i8, i8* bitcast ([2 x i32]* @_ZN1AIjLj9EE2SVE to i8*), i64 4) to i32*) } }, section "llvm.metadata" +//CHECK: @llvm.global.annotations = appending global [2 x { i8*, i8*, i8*, i32, i8* }] [{ i8*, i8*, i8*, i32, i8* } { i8* bitcast (void (%struct.A*)* @_ZN1AIjLj9EE4testILi8EEEvv to i8*), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @[[STR:.*]], i32 0, i32 0), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* @[[STR1:.*]], i32 0, i32 0), i32 {{.*}}, i8* bitcast ({ i32, i8*, i32 }* @[[ARGS:.*]] to i8*) }, { i8*, i8*, i8*, i32, i8* } { i8* bitcast (void (%struct.A*)* @_ZN1AIjLj9EE5test2Ev to i8*), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.6, i32 0, i32 0), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* @.str.1, i32 0, i32 0), i32 24, i8* bitcast ({ %struct.Struct }* @[[ARGS2]] to i8*) }] + +constexpr const char* str() { + return "abc"; +} + +template +struct Struct { + T t1; + T t2; +}; + +template +struct A { + static constexpr const T SV[] = {V, V + 1}; + template __attribute__((annotate("test", V, str(), I))) void test() {} + __attribute__((annotate("test", Struct{&SV[0], &SV[1]}))) void test2() {} +}; + +void t() { + A a; + a.test<8>(); + a.test2(); +} + +template +struct B { +template +struct foo { + int v __attribute__((annotate("v_ann_0", str(), 90, V))) __attribute__((annotate("v_ann_1", V1))); +}; +}; + +static B::foo gf; + +// CHECK-LABEL: @main( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ARGC_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ARGV_ADDR:%.*]] = alloca i8**, align 8 +// CHECK-NEXT: [[F:%.*]] = alloca %"struct.B::foo", align 4 +// CHECK-NEXT: store i32 0, i32* [[RETVAL]], align 4 +// CHECK-NEXT: store i32 [[ARGC:%.*]], i32* [[ARGC_ADDR]], align 4 +// CHECK-NEXT: store i8** [[ARGV:%.*]], i8*** [[ARGV_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[ARGC_ADDR]], align 4 +// CHECK-NEXT: [[V:%.*]] = getelementptr inbounds %"struct.B::foo", %"struct.B::foo"* [[F]], i32 0, i32 0 +// CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[V]] to i8* +// CHECK-NEXT: [[TMP2:%.*]] = call i8* @llvm.ptr.annotation.p0i8(i8* [[TMP1]], i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* @.str.1, i32 0, i32 0), i32 {{.*}}, i8* bitcast ({ i8*, i32, i32 }* @.args to i8*)) +// CHECK-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32* +// CHECK-NEXT: [[TMP4:%.*]] = bitcast i32* [[TMP3]] to i8* +// CHECK-NEXT: [[TMP5:%.*]] = call i8* @llvm.ptr.annotation.p0i8(i8* [[TMP4]], i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i32 0, i32 0), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* @.str.1, i32 0, i32 0), i32 {{.*}}, i8* bitcast ({ i32 }* @.args.4 to i8*)) +// CHECK-NEXT: [[TMP6:%.*]] = bitcast i8* [[TMP5]] to i32* +// CHECK-NEXT: store i32 [[TMP0]], i32* [[TMP6]], align 4 +// CHECK-NEXT: [[TMP7:%.*]] = load i32, i32* [[ARGC_ADDR]], align 4 +// CHECK-NEXT: [[TMP8:%.*]] = call i8* @llvm.ptr.annotation.p0i8(i8* bitcast (%"struct.B::foo"* @_ZL2gf to i8*), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* @.str.1, i32 0, i32 0), i32 {{.*}}, i8* bitcast ({ i8*, i32, i64 }* @.args.5 to i8*)) +// CHECK-NEXT: [[TMP9:%.*]] = bitcast i8* [[TMP8]] to i32* +// CHECK-NEXT: [[TMP10:%.*]] = bitcast i32* [[TMP9]] to i8* +// CHECK-NEXT: [[TMP11:%.*]] = call i8* @llvm.ptr.annotation.p0i8(i8* [[TMP10]], i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i32 0, i32 0), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* @.str.1, i32 0, i32 0), i32 {{.*}}, i8* bitcast ({ i32 }* @.args.4 to i8*)) +// CHECK-NEXT: [[TMP12:%.*]] = bitcast i8* [[TMP11]] to i32* +// CHECK-NEXT: store i32 [[TMP7]], i32* [[TMP12]], align 4 +// CHECK-NEXT: ret i32 0 +// +int main(int argc, char **argv) { + B::foo f; + f.v = argc; + gf.v = argc; + return 0; +} diff --git a/clang/test/CodeGenCXX/attr-annotate2.cpp b/clang/test/CodeGenCXX/attr-annotate2.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-annotate2.cpp @@ -0,0 +1,22 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 %s -S -emit-llvm -triple x86_64-unknown-linux-gnu -o - | FileCheck %s + +// CHECK: @[[STR:.*]] = private unnamed_addr constant [45 x i8] c"_Generic selection expression should be fine\00", section "llvm.metadata" +// CHECK-NEXT: @[[FILENAME:.*]] = private unnamed_addr constant {{.*}}, section "llvm.metadata" +// CHECK-NEXT: @[[ARGS:.*]] = private unnamed_addr constant { i32 } zeroinitializer, section "llvm.metadata" + +// CHECK-LABEL: @_Z1fv( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[N:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[J:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 10, i32* [[N]], align 4 +// CHECK-NEXT: [[J1:%.*]] = bitcast i32* [[J]] to i8* +// CHECK-NEXT: call void @llvm.var.annotation(i8* [[J1]], i8* getelementptr inbounds ([45 x i8], [45 x i8]* @[[STR]], i32 0, i32 0), i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* @[[FILENAME]], i32 0, i32 0), i32 {{.*}}, i8* bitcast ({ i32 }* @[[ARGS]] to i8*)) +// CHECK-NEXT: store i32 0, i32* [[J]], align 4 +// CHECK-NEXT: ret void +// +void f() { + int n = 10; + [[clang::annotate("_Generic selection expression should be fine", _Generic(n, int : 0, default : 1))]] + int j = 0; // second arg should resolve to 0 fine +} diff --git a/clang/test/Misc/pragma-attribute-cxx.cpp b/clang/test/Misc/pragma-attribute-cxx.cpp --- a/clang/test/Misc/pragma-attribute-cxx.cpp +++ b/clang/test/Misc/pragma-attribute-cxx.cpp @@ -21,11 +21,15 @@ // CHECK: CXXMethodDecl{{.*}} testMethod1 // CHECK-NEXT: ParmVarDecl{{.*}} param // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NEXT: CXXConstructorDecl // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NEXT: CXXMethodDecl{{.*}} operator-> // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral #pragma clang attribute push (__attribute__((annotate("method"))), apply_to=any(record, field, variable, function, namespace, type_alias)) @@ -36,19 +40,25 @@ // CHECK-LABEL: CXXMethodDecl{{.*}}prev{{.*}} testMethod1 // CHECK-NEXT: ParmVarDecl{{.*}} param // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NEXT: AnnotateAttr{{.*}} "method" +// CHECK-NEXT: StringLiteral // CHECK-NEXT: CompoundStmt // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NEXT: AnnotateAttr{{.*}} "method" +// CHECK-NEXT: StringLiteral namespace testNamespace { } // CHECK-LABEL: NamespaceDecl{{.*}} testNamespace // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral class testClassForward; // CHECK-LABEL: CXXRecordDecl{{.*}} testClassForward // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral namespace testNamespaceAlias = testNamespace; // CHECK-LABEL: NamespaceAliasDecl{{.*}} testNamespaceAlias @@ -68,6 +78,7 @@ // CHECK: CXXCatchStmt // CHECK-NEXT: VarDecl{{.*}} testCatch // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral void testLambdaMethod() { auto l = [] () { }; @@ -79,6 +90,7 @@ // CHECK: CXXMethodDecl{{.*}} operator() // CHECK-NEXT: CompoundStmt // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral #pragma clang attribute pop diff --git a/clang/test/Misc/pragma-attribute-objc.m b/clang/test/Misc/pragma-attribute-objc.m --- a/clang/test/Misc/pragma-attribute-objc.m +++ b/clang/test/Misc/pragma-attribute-objc.m @@ -8,6 +8,7 @@ // CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface1 // CHECK-NEXT: ObjCImplementation // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NEXT: ObjCSubclassingRestrictedAttr{{.*}} // CHECK-NOT: AnnotateAttr @@ -17,24 +18,29 @@ int testIvar1; // CHECK-LABEL: ObjCIvarDecl{{.*}} testIvar1 // CHECK-NEXT: AnnotateAttr{{.*}} "test" + // CHECK-NEXT: StringLiteral // CHECK-NOT: ObjCSubclassingRestrictedAttr } @property int testProp1; // CHECK-LABEL: ObjCPropertyDecl{{.*}} testProp1 // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NOT: ObjCSubclassingRestrictedAttr - (void)testIm:(int) x; // CHECK-LABEL: ObjCMethodDecl{{.*}}testIm // CHECK-NEXT: ParmVarDecl{{.*}} x // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NOT: ObjCSubclassingRestrictedAttr + (void)testCm; // CHECK-LABEL: ObjCMethodDecl{{.*}}testCm // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NOT: ObjCSubclassingRestrictedAttr // Implicit getters/setters shouldn't receive the attributes. @@ -56,6 +62,7 @@ int testIvar2; // CHECK-LABEL: ObjCIvarDecl{{.*}} testIvar2 // CHECK-NEXT: AnnotateAttr{{.*}} "test" + // CHECK-NEXT: StringLiteral // CHECK-NOT: ObjCSubclassingRestrictedAttr } @@ -66,8 +73,10 @@ // CHECK-NEXT: ImplicitParamDecl // CHECK-NEXT: ParmVarDecl{{.*}} x // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NEXT: CompoundStmt // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NOT: ObjCSubclassingRestrictedAttr } @@ -89,8 +98,10 @@ // CHECK-LABEL: ObjCInterfaceDecl{{.*}}testImplWithoutInterface // CHECK-NEXT: ObjCImplementation // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NEXT: ObjCSubclassingRestrictedAttr // CHECK-NEXT: AnnotateAttr{{.*}} "applied at container start" +// CHECK-NEXT: StringLiteral // CHECK-LABEL: ObjCImplementationDecl{{.*}}testImplWithoutInterface // CHECK-NOT: AnnotateAttr @@ -103,12 +114,14 @@ @protocol testProtocol // CHECK-LABEL: ObjCProtocolDecl{{.*}}testProtocol // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NOT: ObjCSubclassingRestrictedAttr // CHECK-NOT: AnnotateAttr - (void)testProtIm; // CHECK-LABEL: ObjCMethodDecl{{.*}}testProtIm // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NOT: ObjCSubclassingRestrictedAttr @end @@ -116,6 +129,7 @@ @protocol testForwardProtocol; // CHECK-LABEL: ObjCProtocolDecl{{.*}}testForwardProtocol // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NOT: ObjCSubclassingRestrictedAttr @@ -152,6 +166,7 @@ @interface testInterface3 // CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface3 // CHECK-NEXT: AnnotateAttr{{.*}} "test" +// CHECK-NEXT: StringLiteral // CHECK-NOT: ObjCSubclassingRestrictedAttr @end diff --git a/clang/test/Parser/access-spec-attrs.cpp b/clang/test/Parser/access-spec-attrs.cpp --- a/clang/test/Parser/access-spec-attrs.cpp +++ b/clang/test/Parser/access-spec-attrs.cpp @@ -5,7 +5,7 @@ void foo(); private __attribute__((annotate("foobar"))): void bar(); -private __attribute__((annotate())): // expected-error {{'annotate' attribute takes one argument}} +private __attribute__((annotate())): // expected-error {{'annotate' attribute takes at least 1 argument}} }; void f(X x) { diff --git a/clang/test/Parser/objc-implementation-attrs.m b/clang/test/Parser/objc-implementation-attrs.m --- a/clang/test/Parser/objc-implementation-attrs.m +++ b/clang/test/Parser/objc-implementation-attrs.m @@ -41,7 +41,7 @@ I5 *i5; -// expected-error@+1 2 {{'annotate' attribute takes one argument}} +// expected-error@+1 2 {{'annotate' attribute takes at least 1 argument}} #pragma clang attribute push (__attribute__((annotate)), apply_to=objc_implementation) @interface I6 @end @interface I6 (MyCat) @end diff --git a/clang/test/Sema/annotate.c b/clang/test/Sema/annotate.c --- a/clang/test/Sema/annotate.c +++ b/clang/test/Sema/annotate.c @@ -5,8 +5,8 @@ [[clang::annotate("bar")]] int x2; __attribute__((annotate(1))) int y; // expected-error {{'annotate' attribute requires a string}} [[clang::annotate(1)]] int y2; // expected-error {{'annotate' attribute requires a string}} - __attribute__((annotate("bar", 1))) int z; // expected-error {{'annotate' attribute takes one argument}} - [[clang::annotate("bar", 1)]] int z2; // expected-error {{'annotate' attribute takes one argument}} + __attribute__((annotate("bar", 1))) int z; + [[clang::annotate("bar", 1)]] int z2; int u = __builtin_annotation(z, (char*) 0); // expected-error {{second argument to __builtin_annotation must be a non-wide string constant}} int v = __builtin_annotation(z, (char*) L"bar"); // expected-error {{second argument to __builtin_annotation must be a non-wide string constant}} diff --git a/clang/test/Sema/pragma-attribute.c b/clang/test/Sema/pragma-attribute.c --- a/clang/test/Sema/pragma-attribute.c +++ b/clang/test/Sema/pragma-attribute.c @@ -7,18 +7,18 @@ #pragma clang attribute pop // expected-note {{'#pragma clang attribute push' regions ends here}} // Ensure we only report any errors once. -#pragma clang attribute push (__attribute__((annotate)), apply_to = function) // expected-error 4 {{'annotate' attribute takes one argument}} +#pragma clang attribute push (__attribute__((annotate)), apply_to = function) // expected-error 4 {{'annotate' attribute takes at least 1 argument}} void test5_begin(); // expected-note {{when applied to this declaration}} void test5_1(); // expected-note {{when applied to this declaration}} -#pragma clang attribute push (__attribute__((annotate())), apply_to = function) // expected-error 2 {{'annotate' attribute takes one argument}} +#pragma clang attribute push (__attribute__((annotate())), apply_to = function) // expected-error 2 {{'annotate' attribute takes at least 1 argument}} void test5_2(); // expected-note 2 {{when applied to this declaration}} -#pragma clang attribute push (__attribute__((annotate("hello", "world"))), apply_to = function) // expected-error {{'annotate' attribute takes one argument}} +#pragma clang attribute push (__attribute__((annotate("hello", "world"))), apply_to = function) -void test5_3(); // expected-note 3 {{when applied to this declaration}} +void test5_3(); // expected-note 2 {{when applied to this declaration}} #pragma clang attribute pop #pragma clang attribute pop @@ -38,8 +38,8 @@ #pragma clang attribute pop -#pragma clang attribute push (__attribute__((annotate())), apply_to = function) // expected-error{{'annotate' attribute takes one argument}} -#pragma clang attribute (__attribute__((annotate())), apply_to = function) // expected-error{{'annotate' attribute takes one argument}} +#pragma clang attribute push (__attribute__((annotate())), apply_to = function) // expected-error{{'annotate' attribute takes at least 1 argument}} +#pragma clang attribute (__attribute__((annotate())), apply_to = function) // expected-error{{'annotate' attribute takes at least 1 argument}} void fun(); // expected-note 2 {{when applied to this declaration}} @@ -48,11 +48,11 @@ #pragma clang attribute push -#pragma clang attribute (__attribute__((annotate())), apply_to = function) // expected-error 2 {{'annotate' attribute takes one argument}} +#pragma clang attribute (__attribute__((annotate())), apply_to = function) // expected-error 2 {{'annotate' attribute takes at least 1 argument}} void fun2(); // expected-note {{when applied to this declaration}} -#pragma clang attribute push (__attribute__((annotate())), apply_to = function) // expected-error{{'annotate' attribute takes one argument}} +#pragma clang attribute push (__attribute__((annotate())), apply_to = function) // expected-error{{'annotate' attribute takes at least 1 argument}} void fun3(); // expected-note 2 {{when applied to this declaration}} #pragma clang attribute pop diff --git a/clang/test/SemaCXX/attr-annotate.cpp b/clang/test/SemaCXX/attr-annotate.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/attr-annotate.cpp @@ -0,0 +1,130 @@ +// RUN: %clang_cc1 -std=gnu++20 -fsyntax-only -verify %s + +template +struct enable_if { + using type= Type; +}; + +template +struct enable_if {}; + +template +struct is_same { + static constexpr bool value = false; +}; + +template +struct is_same { + static constexpr bool value = true; +}; + +constexpr const char *str() { + return "abc"; +} + +template::value, int>::type = 0> +constexpr T fail_on_int(T t) {return t;} +// expected-note@-1 {{candidate template ignored: requirement}} + +namespace test0 { + template + struct A { + [[clang::annotate("test", fail_on_int(v))]] void t() {} + // expected-error@-1 {{no matching function for call to 'fail_on_int'}} + [[clang::annotate("test", (typename enable_if::value, int>::type)v)]] void t1() {} + // expected-error@-1 {{failed requirement}} + }; + A a; +// expected-note@-1 {{in instantiation of template class}} + A a1; +// expected-note@-1 {{in instantiation of template class}} + A a2; + + template + struct B { + [[clang::annotate("test", (T{}, 9))]] void t() {} + // expected-error@-1 {{illegal initializer type 'void'}} + }; + B b; + B b1; +// expected-note@-1 {{in instantiation of template class}} +} + +namespace test1 { +int g_i; // expected-note {{declared here}} + +[[clang::annotate("test", "arg")]] void t3() {} + +template +struct B { + static T b; // expected-note {{declared here}} + static constexpr T cb = V; + template + struct foo { + static T1 f; // expected-note {{declared here}} + static constexpr T1 cf = V1; + int v __attribute__((annotate("v_ann_0", str(), 90, V, g_i))) __attribute__((annotate("v_ann_1", V1))); + // expected-error@-1 {{'annotate' attribute requires parameter 4 to be a constant expression}} + // expected-note@-2 {{is not allowed in a constant expression}} + [[clang::annotate("qdwqwd", cf, cb)]] void t() {} + [[clang::annotate("qdwqwd", f, cb)]] void t1() {} + // expected-error@-1 {{'annotate' attribute requires parameter 1 to be a constant expression}} + // expected-note@-2 {{is not allowed in a constant expression}} + [[clang::annotate("jui", b, cf)]] void t2() {} + // expected-error@-1 {{'annotate' attribute requires parameter 1 to be a constant expression}} + // expected-note@-2 {{is not allowed in a constant expression}} + [[clang::annotate("jui", (b, 0), cf)]] [[clang::annotate("jui", &b, cf, &foo::t2, str())]] void t3() {} + }; +}; + +static B::foo gf; // expected-note {{in instantiation of}} +static B gf1; + +} // namespace test1 + +namespace test2 { + +template +int f() { + [[clang::annotate("test", I)]] int v = 0; // expected-note {{declared here}} + [[clang::annotate("test", v)]] int v2 = 0; + // expected-error@-1 {{'annotate' attribute requires parameter 1 to be a constant expression}} + // expected-note@-2 {{is not allowed in a constant expression}} + [[clang::annotate("test", rtyui)]] int v3 = 0; + // expected-error@-1 {{use of undeclared identifier 'rtyui'}} +} + +void test() {} +} + +namespace test3 { + +void f() { + int n = 10; + int vla[n]; + + [[clang::annotate("vlas are awful", sizeof(vla))]] int i = 0; // reject, the sizeof is not unevaluated + // expected-error@-1 {{'annotate' attribute requires parameter 1 to be a constant expression}} + // expected-note@-2 {{subexpression not valid in a constant expression}} + [[clang::annotate("_Generic selection expression should be fine", _Generic(n, int : 0, default : 1))]] + int j = 0; // second arg should resolve to 0 fine +} +void designator(); +[[clang::annotate("function designators?", designator)]] int k = 0; // Should work? + +void self() { + [[clang::annotate("function designators?", self)]] int k = 0; +} + +} + +namespace test4 { +constexpr int foldable_but_invalid() { + int *A = new int(0); +// expected-note@-1 {{allocation performed here was not deallocated}} + return *A; +} + +[[clang::annotate("", foldable_but_invalid())]] void f1() {} +// expected-error@-1 {{'annotate' attribute requires parameter 1 to be a constant expression}} +} diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -943,11 +943,11 @@ // def int_var_annotation : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, - llvm_ptr_ty, llvm_i32_ty], + llvm_ptr_ty, llvm_i32_ty, llvm_ptr_ty], [IntrWillReturn], "llvm.var.annotation">; def int_ptr_annotation : Intrinsic<[LLVMAnyPointerType], [LLVMMatchType<0>, llvm_ptr_ty, llvm_ptr_ty, - llvm_i32_ty], + llvm_i32_ty, llvm_ptr_ty], [IntrWillReturn], "llvm.ptr.annotation">; def int_annotation : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, llvm_ptr_ty, diff --git a/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll b/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll --- a/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll +++ b/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll @@ -15,8 +15,8 @@ ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0i8(i64 1, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0i8(i64 1, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0i8(i8* undef, i1 true, i1 true, i1 true) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret i32 undef ; ; CHECK-THROUGHPUT-LABEL: 'trivially_free' @@ -31,8 +31,8 @@ ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0i8(i64 1, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0i8(i64 1, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0i8(i8* undef, i1 true, i1 true, i1 true) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret i32 undef ; %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) @@ -49,8 +49,8 @@ call void @llvm.lifetime.start.p0i8(i64 1, i8* undef) call void @llvm.lifetime.end.p0i8(i64 1, i8* undef) %a5 = call i64 @llvm.objectsize.i64.p0i8(i8* undef, i1 1, i1 1, i1 1) - %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef) - call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef) + %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) + call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) ret i32 undef } @@ -68,8 +68,8 @@ declare void @llvm.lifetime.start.p0i8(i64, i8*) declare void @llvm.lifetime.end.p0i8(i64, i8*) declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, i1) -declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32) -declare void @llvm.var.annotation(i8*, i8*, i8*, i32) +declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32, i8*) +declare void @llvm.var.annotation(i8*, i8*, i8*, i32, i8*) !0 = !DILocalVariable(scope: !1) diff --git a/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll b/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll --- a/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll +++ b/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll @@ -17,8 +17,8 @@ ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0i8(i64 1, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0i8(i64 1, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0i8(i8* undef, i1 true, i1 true, i1 true) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret i32 undef ; ; CHECK-THROUGHPUT-LABEL: 'trivially_free' @@ -33,8 +33,8 @@ ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0i8(i64 1, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0i8(i64 1, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0i8(i8* undef, i1 true, i1 true, i1 true) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret i32 undef ; %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) @@ -51,8 +51,8 @@ call void @llvm.lifetime.start.p0i8(i64 1, i8* undef) call void @llvm.lifetime.end.p0i8(i64 1, i8* undef) %a5 = call i64 @llvm.objectsize.i64.p0i8(i8* undef, i1 1, i1 1, i1 1) - %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef) - call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef) + %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) + call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) ret i32 undef } @@ -70,8 +70,8 @@ declare void @llvm.lifetime.start.p0i8(i64, i8*) declare void @llvm.lifetime.end.p0i8(i64, i8*) declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, i1) -declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32) -declare void @llvm.var.annotation(i8*, i8*, i8*, i32) +declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32, i8*) +declare void @llvm.var.annotation(i8*, i8*, i8*, i32, i8*) !0 = !DILocalVariable(scope: !1) diff --git a/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll b/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll --- a/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll +++ b/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll @@ -15,8 +15,8 @@ ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0i8(i64 1, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0i8(i64 1, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0i8(i8* undef, i1 true, i1 true, i1 true) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret i32 undef ; ; CHECK-THROUGHPUT-LABEL: 'trivially_free' @@ -31,8 +31,8 @@ ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0i8(i64 1, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0i8(i64 1, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0i8(i8* undef, i1 true, i1 true, i1 true) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret i32 undef ; %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) @@ -49,8 +49,8 @@ call void @llvm.lifetime.start.p0i8(i64 1, i8* undef) call void @llvm.lifetime.end.p0i8(i64 1, i8* undef) %a5 = call i64 @llvm.objectsize.i64.p0i8(i8* undef, i1 1, i1 1, i1 1) - %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef) - call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef) + %a6 = call i8* @llvm.ptr.annotation.p0i8(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) + call void @llvm.var.annotation(i8* undef, i8* undef, i8* undef, i32 undef, i8* undef) ret i32 undef } @@ -68,8 +68,8 @@ declare void @llvm.lifetime.start.p0i8(i64, i8*) declare void @llvm.lifetime.end.p0i8(i64, i8*) declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, i1) -declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32) -declare void @llvm.var.annotation(i8*, i8*, i8*, i32) +declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32, i8*) +declare void @llvm.var.annotation(i8*, i8*, i8*, i32, i8*) !0 = !DILocalVariable(scope: !1) diff --git a/llvm/test/CodeGen/Generic/ptr-annotate.ll b/llvm/test/CodeGen/Generic/ptr-annotate.ll --- a/llvm/test/CodeGen/Generic/ptr-annotate.ll +++ b/llvm/test/CodeGen/Generic/ptr-annotate.ll @@ -10,9 +10,9 @@ define void @foo() { entry: %m = alloca i8, align 4 - %0 = call i8* @llvm.ptr.annotation.p0i8(i8* %m, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str1, i32 0, i32 0), i32 2) + %0 = call i8* @llvm.ptr.annotation.p0i8(i8* %m, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str1, i32 0, i32 0), i32 2, i8* null) store i8 1, i8* %0, align 4 ret void } -declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32) #1 +declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32, i8*) #1 diff --git a/llvm/test/Transforms/InstCombine/assume_inevitable.ll b/llvm/test/Transforms/InstCombine/assume_inevitable.ll --- a/llvm/test/Transforms/InstCombine/assume_inevitable.ll +++ b/llvm/test/Transforms/InstCombine/assume_inevitable.ll @@ -15,7 +15,7 @@ ; CHECK-NEXT: [[DUMMY_EQ:%.*]] = icmp ugt i32 [[LOADRES]], 42 ; CHECK-NEXT: tail call void @llvm.assume(i1 [[DUMMY_EQ]]) ; CHECK-NEXT: [[M_I8:%.*]] = bitcast i64* [[M]] to i8* -; CHECK-NEXT: [[M_A:%.*]] = call i8* @llvm.ptr.annotation.p0i8(i8* nonnull [[M_I8]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str1, i64 0, i64 0), i32 2) +; CHECK-NEXT: [[M_A:%.*]] = call i8* @llvm.ptr.annotation.p0i8(i8* nonnull [[M_I8]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str1, i64 0, i64 0), i32 2, i8* null) ; CHECK-NEXT: [[M_X:%.*]] = bitcast i8* [[M_A]] to i64* ; CHECK-NEXT: [[OBJSZ:%.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* [[C:%.*]], i1 false, i1 false, i1 false) ; CHECK-NEXT: store i64 [[OBJSZ]], i64* [[M_X]], align 4 @@ -44,7 +44,7 @@ call void @llvm.lifetime.end.p0i8(i64 1, i8* %dummy) %m_i8 = bitcast i64* %m to i8* - %m_a = call i8* @llvm.ptr.annotation.p0i8(i8* %m_i8, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str1, i32 0, i32 0), i32 2) + %m_a = call i8* @llvm.ptr.annotation.p0i8(i8* %m_i8, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str1, i32 0, i32 0), i32 2, i8* null) %m_x = bitcast i8* %m_a to i64* %objsz = call i64 @llvm.objectsize.i64.p0i8(i8* %c, i1 false) store i64 %objsz, i64* %m_x @@ -64,7 +64,7 @@ declare i64 @llvm.objectsize.i64.p0i8(i8*, i1) declare i32 @llvm.annotation.i32(i32, i8*, i8*, i32) -declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32) +declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32, i8*) declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)