[Annotation] Allows annotation to carry some additional constant arguments.

This allows using annotation in a much more contexts than it currently has.
especially when annotation with template or constexpr.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D88645
This commit is contained in:
Tyker 2020-10-26 09:58:20 +01:00
parent 8aa60f67dc
commit d3205bbca3
31 changed files with 480 additions and 79 deletions

View File

@ -737,7 +737,7 @@ def AnalyzerNoReturn : InheritableAttr {
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;

View File

@ -2860,7 +2860,7 @@ def err_attribute_sizeless_type : Error<
"%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">;

View File

@ -1023,7 +1023,8 @@ enum AttributeArgumentNType {
AANT_ArgumentIntOrBool,
AANT_ArgumentIntegerConstant,
AANT_ArgumentString,
AANT_ArgumentIdentifier
AANT_ArgumentIdentifier,
AANT_ArgumentConstantExpr,
};
/// These constants match the enumerated choices of
@ -1058,6 +1059,31 @@ inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
return DB;
}
/// 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 <typename ACI,
typename std::enable_if_t<
std::is_same<ACI, AttributeCommonInfo>::value, int> = 0>
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
const ACI &CI) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(CI.getAttrName()),
DiagnosticsEngine::ak_identifierinfo);
return DB;
}
template <typename ACI,
typename std::enable_if_t<
std::is_same<ACI, AttributeCommonInfo>::value, int> = 0>
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
const ACI* CI) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(CI->getAttrName()),
DiagnosticsEngine::ak_identifierinfo);
return DB;
}
} // namespace clang
#endif // LLVM_CLANG_SEMA_ATTRIBUTELIST_H

View File

@ -9987,6 +9987,10 @@ public:
/// 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<Expr *> Args);
/// AddLaunchBoundsAttr - Adds a launch_bounds attribute to a particular
/// declaration.
void AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI,

View File

@ -3403,7 +3403,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// non-wide string literal, potentially casted, so the cast<> is safe.
const Expr *AnnotationStrExpr = E->getArg(1)->IgnoreParenCasts();
StringRef Str = cast<StringLiteral>(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:

View File

@ -2234,13 +2234,16 @@ void CodeGenFunction::emitAlignmentAssumption(llvm::Value *PtrValue,
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<llvm::Value *, 5> 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);
}
@ -2251,7 +2254,7 @@ void CodeGenFunction::EmitVarAnnotations(const VarDecl *D, llvm::Value *V) {
for (const auto *I : D->specific_attrs<AnnotateAttr>())
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,
@ -2268,7 +2271,7 @@ Address CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D,
// 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);
}

View File

@ -4326,7 +4326,8 @@ public:
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);

View File

@ -2341,13 +2341,48 @@ llvm::Constant *CodeGenModule::EmitAnnotationLineNo(SourceLocation L) {
return llvm::ConstantInt::get(Int32Ty, LineNo);
}
llvm::Constant *CodeGenModule::EmitAnnotationArgs(const AnnotateAttr *Attr) {
ArrayRef<Expr *> 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<clang::ConstantExpr>(E)->getAPValueResult());
}
llvm::Constant *&Lookup = AnnotationArgs[ID.ComputeHash()];
if (Lookup)
return Lookup;
llvm::SmallVector<llvm::Constant *, 4> LLVMArgs;
LLVMArgs.reserve(Exprs.size());
ConstantEmitter ConstEmiter(*this);
llvm::transform(Exprs, std::back_inserter(LLVMArgs), [&](const Expr *E) {
const auto *CE = cast<clang::ConstantExpr>(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) {
@ -2356,11 +2391,12 @@ llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV,
}
// 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);
}

View File

@ -413,6 +413,9 @@ private:
/// Map used to get unique annotation strings.
llvm::StringMap<llvm::Constant*> AnnotationStrings;
/// Used for uniquing of annotation arguments.
llvm::DenseMap<unsigned, llvm::Constant *> AnnotationArgs;
llvm::StringMap<llvm::GlobalVariable *> CFConstantStringMap;
llvm::DenseMap<llvm::Constant *, llvm::GlobalVariable *> ConstantStringMap;
@ -1241,6 +1244,9 @@ public:
/// 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

View File

@ -3682,20 +3682,68 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL));
}
void Sema::AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI,
StringRef Str, MutableArrayRef<Expr *> Args) {
auto *Attr = AnnotateAttr::Create(Context, Str, Args.data(), Args.size(), CI);
llvm::SmallVector<PartialDiagnosticAt, 8> 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, Context);
/// Result means the expression can be folded to a constant.
/// Note.empty() means the expression is a valid constant expression in the
/// current language mode.
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<AnnotateAttr>()) {
if (I->getAnnotation() == Str)
return;
llvm::SmallVector<Expr *, 4> 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) {

View File

@ -181,6 +181,22 @@ static void instantiateDependentAllocAlignAttr(
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<Expr *, 4> 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 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
if (const auto *Annotate = dyn_cast<AnnotateAttr>(TmplAttr)) {
instantiateDependentAnnotationAttr(*this, TemplateArgs, Annotate, New);
continue;
}
if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) {
instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl,

View File

@ -252,10 +252,12 @@ int mergeAttrTest() __attribute__((unused,no_thread_safety_analysis));
// 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

View File

@ -15,12 +15,12 @@ int main(int argc, char **argv) {
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;
}

View File

@ -21,13 +21,13 @@ __attribute((address_space(1))) __attribute__((annotate("addrspace1_ann"))) char
// 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 @@ __attribute((address_space(1))) __attribute__((annotate("addrspace1_ann"))) char
// 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*), {{.*}}

View File

@ -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 }

View File

@ -34,9 +34,9 @@ void local(void) {
// 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 @@ void undef(void) {
// 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)
}

View File

@ -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<typename T>
struct Struct {
T t1;
T t2;
};
template<typename T, T V>
struct A {
static constexpr const T SV[] = {V, V + 1};
template <int I> __attribute__((annotate("test", V, str(), I))) void test() {}
__attribute__((annotate("test", Struct<const T*>{&SV[0], &SV[1]}))) void test2() {}
};
void t() {
A<unsigned, 9> a;
a.test<8>();
a.test2();
}
template<typename T, T V>
struct B {
template<typename T1, T1 V1>
struct foo {
int v __attribute__((annotate("v_ann_0", str(), 90, V))) __attribute__((annotate("v_ann_1", V1)));
};
};
static B<int long, -1>::foo<unsigned, 9> 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<int, 7>::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<int, 7>::foo", %"struct.B<int, 7>::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<long, -1>::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<int, 7>::foo<unsigned, 9> f;
f.v = argc;
gf.v = argc;
return 0;
}

View File

@ -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
}

View File

@ -21,11 +21,15 @@ class testClass2 {
// 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 @@ void testClass2::testMethod1(int param) {
// 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 @@ void testCatchVariable() {
// CHECK: CXXCatchStmt
// CHECK-NEXT: VarDecl{{.*}} testCatch
// CHECK-NEXT: AnnotateAttr{{.*}} "test"
// CHECK-NEXT: StringLiteral
void testLambdaMethod() {
auto l = [] () { };
@ -79,6 +90,7 @@ void testLambdaMethod() {
// CHECK: CXXMethodDecl{{.*}} operator()
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: AnnotateAttr{{.*}} "test"
// CHECK-NEXT: StringLiteral
#pragma clang attribute pop

View File

@ -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

View File

@ -5,7 +5,7 @@ public __attribute__((unavailable)): // expected-error {{access specifier can on
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) {

View File

@ -41,7 +41,7 @@ typedef int AVAIL_ATTR unavail_int; // expected-note {{marked as being introduce
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

View File

@ -5,8 +5,8 @@ void __attribute__((annotate("foo"))) foo(float *a) {
[[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}}

View File

@ -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 @@ __attribute__((always_inline)) void optnone3() { } // expected-warning {{'always
#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 @@ void fun(); // expected-note 2 {{when applied to this declaration}}
#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

View File

@ -0,0 +1,130 @@
// RUN: %clang_cc1 -std=gnu++20 -fsyntax-only -verify %s
template<bool If, typename Type>
struct enable_if {
using type= Type;
};
template<typename Type>
struct enable_if<false, Type> {};
template<typename T1, typename T2>
struct is_same {
static constexpr bool value = false;
};
template<typename T1>
struct is_same<T1, T1> {
static constexpr bool value = true;
};
constexpr const char *str() {
return "abc";
}
template<typename T, typename enable_if<!is_same<int, T>::value, int>::type = 0>
constexpr T fail_on_int(T t) {return t;}
// expected-note@-1 {{candidate template ignored: requirement}}
namespace test0 {
template<typename T, T v>
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<!is_same<long, T>::value, int>::type)v)]] void t1() {}
// expected-error@-1 {{failed requirement}}
};
A<int, 9> a;
// expected-note@-1 {{in instantiation of template class}}
A<long, 7> a1;
// expected-note@-1 {{in instantiation of template class}}
A<unsigned long, 6> a2;
template<typename T>
struct B {
[[clang::annotate("test", (T{}, 9))]] void t() {}
// expected-error@-1 {{illegal initializer type 'void'}}
};
B<int> b;
B<void> 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 <typename T, T V>
struct B {
static T b; // expected-note {{declared here}}
static constexpr T cb = V;
template <typename T1, T1 V1>
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<int long, -1>::foo<unsigned, 9> gf; // expected-note {{in instantiation of}}
static B<int long, -2> gf1;
} // namespace test1
namespace test2 {
template<int I>
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}}
}

View File

@ -953,11 +953,11 @@ def int_eh_sjlj_setup_dispatch : Intrinsic<[], []>;
//
def int_var_annotation : DefaultAttrsIntrinsic<[],
[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 : DefaultAttrsIntrinsic<[LLVMAnyPointerType<llvm_anyint_ty>],
[LLVMMatchType<0>, llvm_ptr_ty, llvm_ptr_ty,
llvm_i32_ty],
llvm_i32_ty, llvm_ptr_ty],
[IntrWillReturn], "llvm.ptr.annotation">;
def int_annotation : DefaultAttrsIntrinsic<[llvm_anyint_ty],
[LLVMMatchType<0>, llvm_ptr_ty,

View File

@ -15,8 +15,8 @@ define i32 @trivially_free() {
; 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 @@ define i32 @trivially_free() {
; 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 @@ define i32 @trivially_free() {
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 i1 @llvm.is.constant.i32(i32)
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)

View File

@ -17,8 +17,8 @@ define i32 @trivially_free() {
; 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 @@ define i32 @trivially_free() {
; 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 @@ define i32 @trivially_free() {
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 i1 @llvm.is.constant.i32(i32)
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)

View File

@ -15,8 +15,8 @@ define i32 @trivially_free() {
; 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 @@ define i32 @trivially_free() {
; 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 @@ define i32 @trivially_free() {
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 i1 @llvm.is.constant.i32(i32)
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)

View File

@ -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

View File

@ -15,7 +15,7 @@ define i32 @assume_inevitable(i32* %a, i32* %b, i8* %c) {
; 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 @@ entry:
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 @@ entry:
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)